FEATURE: Add export poll button (#8370)
This PR aims to make poll results easily exportable to staff in a CSV format, so they can be analyzed in external software. It also makes the export data easily customizable by allowing users to leverage any data explorer query to generate the report. By default, we use a query that ships with data explorer, but user can change the ID in settings or use 0 to disable this feature. One potential upgrade is using the recent work that allows arbitrary group to run data explorer and allow all the groups with access to the configured query to also export polls, but that can be added later. Co-Authored-By: Joffrey JAFFEUX <j.jaffeux@gmail.com>
This commit is contained in:
parent
c498780479
commit
fd0025a735
|
@ -425,7 +425,9 @@ createWidget("discourse-poll-buttons", {
|
|||
const closed = attrs.isClosed;
|
||||
const staffOnly = poll.results === "staff_only";
|
||||
const isStaff = this.currentUser && this.currentUser.staff;
|
||||
const dataExplorerEnabled = this.siteSettings.data_explorer_enabled;
|
||||
const hideResultsDisabled = !staffOnly && (closed || topicArchived);
|
||||
const exportQueryID = this.siteSettings.poll_export_data_explorer_query_id;
|
||||
|
||||
if (attrs.isMultiple && !hideResultsDisabled) {
|
||||
const castVotesDisabled = !attrs.canCastVotes;
|
||||
|
@ -475,6 +477,19 @@ createWidget("discourse-poll-buttons", {
|
|||
}
|
||||
}
|
||||
|
||||
if (isStaff && dataExplorerEnabled && poll.voters > 0 && exportQueryID) {
|
||||
contents.push(
|
||||
this.attach("button", {
|
||||
className: "btn btn-default export-results",
|
||||
label: "poll.export-results.label",
|
||||
title: "poll.export-results.title",
|
||||
icon: "download",
|
||||
disabled: poll.voters === 0,
|
||||
action: "exportResults"
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
if (poll.get("close")) {
|
||||
const closeDate = moment.utc(poll.get("close"));
|
||||
if (closeDate.isValid()) {
|
||||
|
@ -685,6 +700,47 @@ export default createWidget("discourse-poll", {
|
|||
this.state.showResults = !this.state.showResults;
|
||||
},
|
||||
|
||||
exportResults() {
|
||||
const { attrs } = this;
|
||||
const queryID = this.siteSettings.poll_export_data_explorer_query_id;
|
||||
|
||||
// This uses the Data Explorer plugin export as CSV route
|
||||
// There is detection to check if the plugin is enabled before showing the button
|
||||
ajax(`/admin/plugins/explorer/queries/${queryID}/run.csv`, {
|
||||
type: "POST",
|
||||
data: {
|
||||
// needed for data-explorer route compatibility
|
||||
params: JSON.stringify({
|
||||
poll_name: attrs.poll.name,
|
||||
post_id: attrs.post.id.toString() // needed for data-explorer route compatibility
|
||||
}),
|
||||
explain: false,
|
||||
limit: 1000000,
|
||||
download: 1
|
||||
}
|
||||
})
|
||||
.then(csvContent => {
|
||||
const downloadLink = document.createElement("a");
|
||||
const blob = new Blob([csvContent], {
|
||||
type: "text/csv;charset=utf-8;"
|
||||
});
|
||||
downloadLink.href = URL.createObjectURL(blob);
|
||||
downloadLink.setAttribute(
|
||||
"download",
|
||||
`poll-export-${attrs.poll.name}-${attrs.post.id}.csv`
|
||||
);
|
||||
downloadLink.click();
|
||||
downloadLink.remove();
|
||||
})
|
||||
.catch(error => {
|
||||
if (error) {
|
||||
popupAjaxError(error);
|
||||
} else {
|
||||
bootbox.alert(I18n.t("poll.error_while_exporting_results"));
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
showLogin() {
|
||||
this.register.lookup("route:application").send("showLogin");
|
||||
},
|
||||
|
|
|
@ -36,6 +36,10 @@ div.poll {
|
|||
line-height: 2em;
|
||||
}
|
||||
|
||||
:not(:first-child):not(:last-child) {
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.toggle-status {
|
||||
float: right;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,10 @@ en:
|
|||
title: "Back to your votes"
|
||||
label: "Hide results"
|
||||
|
||||
export-results:
|
||||
title: "Export the poll results"
|
||||
label: "Export"
|
||||
|
||||
open:
|
||||
title: "Open the poll"
|
||||
label: "Open"
|
||||
|
@ -80,6 +84,7 @@ en:
|
|||
error_while_toggling_status: "Sorry, there was an error toggling the status of this poll."
|
||||
error_while_casting_votes: "Sorry, there was an error casting your votes."
|
||||
error_while_fetching_voters: "Sorry, there was an error displaying the voters."
|
||||
error_while_exporting_results: "Sorry, there was an error exporting poll results."
|
||||
|
||||
ui_builder:
|
||||
title: Build Poll
|
||||
|
|
|
@ -20,6 +20,7 @@ en:
|
|||
poll_maximum_options: "Maximum number of options allowed in a poll."
|
||||
poll_edit_window_mins: "Number of minutes after post creation during which polls can be edited."
|
||||
poll_minimum_trust_level_to_create: "Define the minimum trust level needed to create polls."
|
||||
poll_export_data_explorer_query_id: "ID of the Data Explorer Query to use for exporting poll results (0 to disable)."
|
||||
|
||||
poll:
|
||||
poll: "poll"
|
||||
|
|
|
@ -14,3 +14,7 @@ plugins:
|
|||
default: 1
|
||||
client: true
|
||||
enum: 'TrustLevelSetting'
|
||||
poll_export_data_explorer_query_id:
|
||||
default: -16
|
||||
min: -9999
|
||||
client: true
|
||||
|
|
Loading…
Reference in New Issue