UX: Improve poll builder UI (#12549)

UX: Improve poll builder UI (#12549)

  • Improve poll validation

  • Redesign poll builder

  • Group all advanced settings under a new section

diff --git a/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6 b/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6
index 2bf034e..ef5bb4a 100644
--- a/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6
+++ b/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6
@@ -1,234 +1,152 @@
-import discourseComputed, { observes } from "discourse-common/utils/decorators";
 import Controller from "@ember/controller";
-import EmberObject from "@ember/object";
+import EmberObject, { action } from "@ember/object";
+import { gt, or } from "@ember/object/computed";
+import { next } from "@ember/runloop";
+import discourseComputed, { observes } from "discourse-common/utils/decorators";
+import ModalFunctionality from "discourse/mixins/modal-functionality";
 import I18n from "I18n";
 
 export const BAR_CHART_TYPE = "bar";
 export const PIE_CHART_TYPE = "pie";
 
-export default Controller.extend({
-  regularPollType: "regular",
-  numberPollType: "number",
-  multiplePollType: "multiple",
-
-  alwaysPollResult: "always",
-  votePollResult: "on_vote",
-  closedPollResult: "on_close",
-  staffPollResult: "staff_only",
-  pollChartTypes: [
-    {
-      name: I18n.t("poll.ui_builder.poll_chart_type.bar"),
-      value: BAR_CHART_TYPE,
-    },
-    {
-      name: I18n.t("poll.ui_builder.poll_chart_type.pie"),
-      value: PIE_CHART_TYPE,
-    },
-  ],
-
-  pollType: null,
-  pollResult: null,
-  pollTitle: null,
-
-  init() {
-    this._super(...arguments);
-    this._setupPoll();
-  },
-
-  @discourseComputed("regularPollType", "numberPollType", "multiplePollType")
-  pollTypes(regularPollType, numberPollType, multiplePollType) {
-    return [
-      {
-        name: I18n.t("poll.ui_builder.poll_type.regular"),
-        value: regularPollType,
-      },
-      {
-        name: I18n.t("poll.ui_builder.poll_type.number"),
-        value: numberPollType,
-      },
-      {
-        name: I18n.t("poll.ui_builder.poll_type.multiple"),
-        value: multiplePollType,
-      },
-    ];
-  },
-
-  @discourseComputed("chartType", "pollType", "numberPollType")
-  isPie(chartType, pollType, numberPollType) {
-    return pollType !== numberPollType && chartType === PIE_CHART_TYPE;
+export const REGULAR_POLL_TYPE = "regular";
+export const NUMBER_POLL_TYPE = "number";
+export const MULTIPLE_POLL_TYPE = "multiple";
+
+const ALWAYS_POLL_RESULT = "always";
+const VOTE_POLL_RESULT = "on_vote";
+const CLOSED_POLL_RESULT = "on_close";
+const STAFF_POLL_RESULT = "staff_only";
+
+export default Controller.extend(ModalFunctionality, {
+  showAdvanced: false,
+
+  pollType: REGULAR_POLL_TYPE,
+  pollTitle: "",
+  pollOptions: null,
+  pollMin: 1,
+  pollMax: 2,
+  pollStep: 1,
+  pollGroups: null,
+  pollAutoClose: null,
+  pollResult: ALWAYS_POLL_RESULT,
+  chartType: BAR_CHART_TYPE,
+  publicPoll: null,
+
+  onShow() {
+    this.setProperties({
+      showAdvanced: false,
+      pollType: REGULAR_POLL_TYPE,
+      pollTitle: null,
+      pollOptions: [EmberObject.create({ value: "" })],
+      pollMin: 1,
+      pollMax: 2,
+      pollStep: 1,
+      pollGroups: null,
+      pollAutoClose: null,
+      pollResult: ALWAYS_POLL_RESULT,
+      chartType: BAR_CHART_TYPE,
+      publicPoll: false,
+    });
   },
 
-  @discourseComputed(
-    "alwaysPollResult",
-    "votePollResult",
-    "closedPollResult",
-    "staffPollResult"
-  )
-  pollResults(
-    alwaysPollResult,
-    votePollResult,
-    closedPollResult,
-    staffPollResult
-  ) {
-    let options = [
+  @discourseComputed
+  pollResults() {
+    const options = [
       {
         name: I18n.t("poll.ui_builder.poll_result.always"),
-        value: alwaysPollResult,
+        value: ALWAYS_POLL_RESULT,
       },
       {
         name: I18n.t("poll.ui_builder.poll_result.vote"),
-        value: votePollResult,
+        value: VOTE_POLL_RESULT,
       },
       {
         name: I18n.t("poll.ui_builder.poll_result.closed"),
-        value: closedPollResult,
+        value: CLOSED_POLL_RESULT,
       },
     ];
+
     if (this.get("currentUser.staff")) {
       options.push({
         name: I18n.t("poll.ui_builder.poll_result.staff"),
-        value: staffPollResult,
+        value: STAFF_POLL_RESULT,
       });
     }
-    return options;
-  },
 
-  @discourseComputed("site.groups")
-  siteGroups(groups) {
-    return groups
-      .map((g) => {
-        // prevents group "everyone" to be listed
-        if (g.id !== 0) {
-          return { name: g.name };
-        }
-      })
-      .filter(Boolean);
+    return options;
   },
 
-  @discourseComputed("pollType", "regularPollType")
-  isRegular(pollType, regularPollType) {
-    return pollType === regularPollType;
+  @discourseComputed("pollType")
+  isRegular(pollType) {
+    return pollType === REGULAR_POLL_TYPE;
   },
 
-  @discourseComputed("pollType", "pollOptionsCount", "multiplePollType")
-  isMultiple(pollType, count, multiplePollType) {
-    return pollType === multiplePollType && count > 0;
+  @discourseComputed("pollType")
+  isNumber(pollType) {
+    return pollType === NUMBER_POLL_TYPE;
   },
 
-  @discourseComputed("pollType", "numberPollType")
-  isNumber(pollType, numberPollType) {
-    return pollType === numberPollType;
+  @discourseComputed("pollType")
+  isMultiple(pollType) {
+    return pollType === MULTIPLE_POLL_TYPE;
   },
 
-  @discourseComputed("isRegular")
-  showMinMax(isRegular) {
-    return !isRegular;
-  },
+  showNumber: or("showAdvanced", "isNumber"),
 
-  @discourseComputed("pollOptions")
+  @discourseComputed("pollOptions.@each.value")
   pollOptionsCount(pollOptions) {
-    if (pollOptions.length === 0) {
-      return 0;
-    }
-
-    let length = 0;
-
-    pollOptions.split("\n").forEach((option) => {
-      if (option.length !== 0) {
-        length += 1;
-      }
-    });
-
-    return length;
+    return pollOptions.filter((option) => option.value.length > 0).length;
   },
 
-  @observes("pollType", "pollOptionsCount")
-  _setPollMax() {
-    const isMultiple = this.isMultiple;
-    const isNumber = this.isNumber;
-    if (!isMultiple && !isNumber) {
-      return;
-    }
-
-    if (isMultiple) {
-      this.set("pollMax", this.pollOptionsCount);
-    } else if (isNumber) {
-      this.set("pollMax", this.siteSettings.poll_maximum_options);
-    }
+  @discourseComputed("site.groups")
+  siteGroups(groups) {
+    // prevents group "everyone" to be listed
+    return groups.filter((g) => g.id !== 0);
   },
 
-  @discourseComputed("isRegular", "isMultiple", "isNumber", "pollOptionsCount")
-  pollMinOptions(isRegular, isMultiple, isNumber, count) {
-    if (isRegular) {
-      return;
-    }
-
-    if (isMultiple) {
-      return this._comboboxOptions(1, count + 1);
-    } else if (isNumber) {
-      return this._comboboxOptions(
-        1,
-        this.siteSettings.poll_maximum_options + 1
-      );
-    }
+  @discourseComputed("chartType", "pollType")
+  isPie(chartType, pollType) {
+    return pollType !== NUMBER_POLL_TYPE && chartType === PIE_CHART_TYPE;
   },
 
-  @discourseComputed(
-    "isRegular",
-    "isMultiple",
-    "isNumber",
-    "pollOptionsCount",
-    "pollMin",
-    "pollStep"
-  )
-  pollMaxOptions(isRegular, isMultiple, isNumber, count, pollMin, pollStep) {
-    if (isRegular) {
-      return;
-    }
-    const pollMinInt = parseInt(pollMin, 10) || 1;
+  canRemoveOption: gt("pollOptions.length", 1),
 
-    if (isMultiple) {
-      return this._comboboxOptions(pollMinInt + 1, count + 1);
-    } else if (isNumber) {
-      let pollStepInt = parseInt(pollStep, 10);
-      if (pollStepInt < 1) {
-        pollStepInt = 1;
+  @observes("pollType", "pollOptionsCount")
+  _setPollMinMax() {
+    if (this.isMultiple) {
+      if (
+        this.pollMin >= this.pollMax ||
+        this.pollMin >= this.pollOptionsCount
+      ) {
+        this.set("pollMin", this.pollOptionsCount > 0 ? 1 : 0);
       }
-      return this._comboboxOptions(
-        pollMinInt + 1,

[... diff too long, it was truncated ...]

GitHub sha: 2081b6e5

This commit appears in #12549 which was approved by eviltrout and ZogStriP. It was merged by nbianca.