Add 'download results as CSV'
This commit is contained in:
parent
d1a58e83a2
commit
1601f4f269
|
@ -100,43 +100,50 @@ const QueryResultComponent = Ember.Component.extend({
|
||||||
});
|
});
|
||||||
}.property('content', 'columns.@each'),
|
}.property('content', 'columns.@each'),
|
||||||
|
|
||||||
|
downloadResult(format) {
|
||||||
|
// Create a frame to submit the form in (?)
|
||||||
|
// to avoid leaving an about:blank behind
|
||||||
|
let windowName = randomIdShort();
|
||||||
|
const newWindowContents = "<body>Click anywhere to close this window once the download finishes.<script>window.onclick=function(){window.close()};</script>";
|
||||||
|
|
||||||
|
let newWindow = window.open('data:text/html;base64,' + btoa(newWindowContents), windowName);
|
||||||
|
|
||||||
|
let form = document.createElement("form");
|
||||||
|
form.setAttribute('id', 'query-download-result');
|
||||||
|
form.setAttribute('method', 'post');
|
||||||
|
form.setAttribute('action', Discourse.getURL('/admin/plugins/explorer/queries/' + this.get('query.id') + '/run.' + format + '?download=1'));
|
||||||
|
form.setAttribute('target', windowName);
|
||||||
|
form.setAttribute('style', 'display:none;');
|
||||||
|
|
||||||
|
function addInput(form, name, value) {
|
||||||
|
let field;
|
||||||
|
field = document.createElement('input');
|
||||||
|
field.setAttribute('name', name);
|
||||||
|
field.setAttribute('value', value);
|
||||||
|
form.appendChild(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
addInput(form, 'params', JSON.stringify(this.get('params')));
|
||||||
|
addInput(form, 'explain', this.get('hasExplain'));
|
||||||
|
addInput(form, 'limit', '1000000');
|
||||||
|
|
||||||
|
Discourse.ajax('/session/csrf.json').then(function(csrf) {
|
||||||
|
addInput(form, 'authenticity_token', csrf.csrf);
|
||||||
|
|
||||||
|
document.body.appendChild(form);
|
||||||
|
form.submit();
|
||||||
|
Em.run.next('afterRender', function() {
|
||||||
|
document.body.removeChild(form);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
actions: {
|
actions: {
|
||||||
downloadResult() {
|
downloadResultJson() {
|
||||||
// Create a frame to submit the form in (?)
|
this.downloadResult('json');
|
||||||
// to avoid leaving an about:blank behind
|
},
|
||||||
let windowName = randomIdShort();
|
downloadResultCsv() {
|
||||||
const newWindowContents = "<body>Click anywhere to close this window once the download finishes.<script>window.onclick=function(){window.close()};</script>";
|
this.downloadResult('csv');
|
||||||
|
|
||||||
let newWindow = window.open('data:text/html;base64,' + btoa(newWindowContents), windowName);
|
|
||||||
|
|
||||||
let form = document.createElement("form");
|
|
||||||
form.setAttribute('id', 'query-download-result');
|
|
||||||
form.setAttribute('method', 'post');
|
|
||||||
form.setAttribute('action', Discourse.getURL('/admin/plugins/explorer/queries/' + this.get('query.id') + '/run.json?download=1'));
|
|
||||||
form.setAttribute('target', windowName);
|
|
||||||
form.setAttribute('style', 'display:none;');
|
|
||||||
|
|
||||||
function addInput(form, name, value) {
|
|
||||||
let field;
|
|
||||||
field = document.createElement('input');
|
|
||||||
field.setAttribute('name', name);
|
|
||||||
field.setAttribute('value', value);
|
|
||||||
form.appendChild(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
addInput(form, 'params', JSON.stringify(this.get('params')));
|
|
||||||
addInput(form, 'explain', this.get('hasExplain'));
|
|
||||||
addInput(form, 'limit', '1000000');
|
|
||||||
|
|
||||||
Discourse.ajax('/session/csrf.json').then(function(csrf) {
|
|
||||||
addInput(form, 'authenticity_token', csrf.csrf);
|
|
||||||
|
|
||||||
document.body.appendChild(form);
|
|
||||||
form.submit();
|
|
||||||
Em.run.next('afterRender', function() {
|
|
||||||
document.body.removeChild(form);
|
|
||||||
})
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<div class="result-info">
|
<div class="result-info">
|
||||||
{{d-button action="downloadResult" icon="download" label="explorer.download_json"}}
|
{{i18n "explorer.download"}}
|
||||||
|
{{d-button action="downloadResultJson" icon="download" label="explorer.download_json"}}
|
||||||
|
{{d-button action="downloadResultCsv" icon="download" label="explorer.download_csv"}}
|
||||||
<div class="result-about">
|
<div class="result-about">
|
||||||
{{duration}}
|
{{duration}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -46,13 +46,15 @@ en:
|
||||||
edit: "Edit"
|
edit: "Edit"
|
||||||
delete: "Delete"
|
delete: "Delete"
|
||||||
recover: "Undelete Query"
|
recover: "Undelete Query"
|
||||||
download_json: "Download Results"
|
download: "Download Results"
|
||||||
|
download_json: "JSON"
|
||||||
|
download_csv: "CSV"
|
||||||
others_dirty: "A query has unsaved changes that will be lost if you navigate away."
|
others_dirty: "A query has unsaved changes that will be lost if you navigate away."
|
||||||
run_time: "Query completed in {{value}} ms."
|
run_time: "Query completed in {{value}} ms."
|
||||||
column: "Column {{number}}"
|
column: "Column {{number}}"
|
||||||
explain_label: "Include query plan?"
|
explain_label: "Include query plan?"
|
||||||
save_params: "Set Defaults"
|
save_params: "Set Defaults"
|
||||||
reset_params: "Reset"
|
reset_params: "Reset"
|
||||||
https_warning: "Use of the Data Explorer on sites not protected by HTTPS is discouraged. Please be careful to not retrieve sensitive information over insecure links."
|
https_warning: "This site is not protected by HTTPS. Please be careful to not retrieve sensitive information over insecure links."
|
||||||
no_queries: "There are no queries. Why not "
|
no_queries: "There are no queries. Why not "
|
||||||
no_queries_hook: "create one?"
|
no_queries_hook: "create one?"
|
||||||
|
|
54
plugin.rb
54
plugin.rb
|
@ -917,8 +917,6 @@ SQL
|
||||||
check_xhr unless params[:download]
|
check_xhr unless params[:download]
|
||||||
query = DataExplorer::Query.find(params[:id].to_i)
|
query = DataExplorer::Query.find(params[:id].to_i)
|
||||||
if params[:download]
|
if params[:download]
|
||||||
response.headers['Content-Disposition'] =
|
|
||||||
"attachment; filename=#{query.slug}@#{Slug.for(Discourse.current_hostname, 'discourse')}-#{Date.today}.dcqresult.json"
|
|
||||||
response.sending_file = true
|
response.sending_file = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -952,23 +950,45 @@ SQL
|
||||||
else
|
else
|
||||||
pg_result = result[:pg_result]
|
pg_result = result[:pg_result]
|
||||||
cols = pg_result.fields
|
cols = pg_result.fields
|
||||||
json = {
|
respond_to do |format|
|
||||||
success: true,
|
format.json do
|
||||||
errors: [],
|
if params[:download]
|
||||||
duration: (result[:duration_secs].to_f * 1000).round(1),
|
response.headers['Content-Disposition'] =
|
||||||
params: query_params,
|
"attachment; filename=#{query.slug}@#{Slug.for(Discourse.current_hostname, 'discourse')}-#{Date.today}.dcqresult.json"
|
||||||
columns: cols,
|
end
|
||||||
}
|
json = {
|
||||||
json[:explain] = result[:explain] if opts[:explain]
|
success: true,
|
||||||
# TODO - special serialization
|
errors: [],
|
||||||
# This is dead code in the client right now
|
duration: (result[:duration_secs].to_f * 1000).round(1),
|
||||||
# if cols.any? { |col_name| special_serialization? col_name }
|
params: query_params,
|
||||||
# json[:relations] = DataExplorer.add_extra_data(pg_result)
|
columns: cols,
|
||||||
# end
|
}
|
||||||
|
json[:explain] = result[:explain] if opts[:explain]
|
||||||
|
# TODO - special serialization
|
||||||
|
# This is dead code in the client right now
|
||||||
|
# if cols.any? { |col_name| special_serialization? col_name }
|
||||||
|
# json[:relations] = DataExplorer.add_extra_data(pg_result)
|
||||||
|
# end
|
||||||
|
|
||||||
json[:rows] = pg_result.values
|
json[:rows] = pg_result.values
|
||||||
|
|
||||||
render json: json
|
render json: json
|
||||||
|
end
|
||||||
|
format.csv do
|
||||||
|
response.headers['Content-Disposition'] =
|
||||||
|
"attachment; filename=#{query.slug}@#{Slug.for(Discourse.current_hostname, 'discourse')}-#{Date.today}.dcqresult.csv"
|
||||||
|
|
||||||
|
require 'csv'
|
||||||
|
text = CSV.generate do |csv|
|
||||||
|
csv << cols
|
||||||
|
pg_result.values.each do |row|
|
||||||
|
csv << row
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
render text: text
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue