Improve validation for polls and improve builder (#12745)

Improve validation for polls and improve builder (#12745)

  • FIX: Show date picker over modal

Previously, scrolling was necessary to see the whole picker.

  • FEATURE: Improve validation for polls

Adds new error messages for each of the edge cases. Previously, it failed with a simple error saying that the minimum value must be less than the maximum value.

  • UX: Copy edit
diff --git a/app/assets/javascripts/discourse/app/templates/components/date-input.hbs b/app/assets/javascripts/discourse/app/templates/components/date-input.hbs
index b86c460..65b7f69 100644
--- a/app/assets/javascripts/discourse/app/templates/components/date-input.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/date-input.hbs
@@ -6,4 +6,6 @@
   input=(action "onChangeDate")
 }}
 
-<div class="picker-container"></div>
+{{#unless useGlobalPickerContainer}}
+  <div class="picker-container"></div>
+{{/unless}}
diff --git a/app/assets/javascripts/discourse/app/templates/components/date-time-input.hbs b/app/assets/javascripts/discourse/app/templates/components/date-time-input.hbs
index 0ec475f..11d9aa4 100644
--- a/app/assets/javascripts/discourse/app/templates/components/date-time-input.hbs
+++ b/app/assets/javascripts/discourse/app/templates/components/date-time-input.hbs
@@ -3,6 +3,7 @@
     date=date
     relativeDate=relativeDate
     onChange=(action "onChangeDate")
+    useGlobalPickerContainer=useGlobalPickerContainer
   }}
 {{/unless}}
 
@@ -19,6 +20,7 @@
     date=date
     relativeDate=relativeDate
     onChange=(action "onChangeDate")
+    useGlobalPickerContainer=useGlobalPickerContainer
   }}
 {{/if}}
 
diff --git a/app/assets/stylesheets/common/base/modal.scss b/app/assets/stylesheets/common/base/modal.scss
index 1b57faa..5e13f27 100644
--- a/app/assets/stylesheets/common/base/modal.scss
+++ b/app/assets/stylesheets/common/base/modal.scss
@@ -430,8 +430,7 @@
   max-width: 420px;
 }
 
-.change-timestamp,
-.poll-ui-builder {
+.change-timestamp {
   #date-container {
     .pika-single {
       position: relative !important; // overriding another important
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 ef5bb4a..af48e1e 100644
--- a/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6
+++ b/plugins/poll/assets/javascripts/controllers/poll-ui-builder.js.es6
@@ -116,6 +116,7 @@ export default Controller.extend(ModalFunctionality, {
   _setPollMinMax() {
     if (this.isMultiple) {
       if (
+        this.pollMin <= 0 ||
         this.pollMin >= this.pollMax ||
         this.pollMin >= this.pollOptionsCount
       ) {
@@ -123,10 +124,11 @@ export default Controller.extend(ModalFunctionality, {
       }
 
       if (
+        this.pollMax <= 0 ||
         this.pollMin >= this.pollMax ||
         this.pollMax > this.pollOptionsCount
       ) {
-        this.set("pollMax", Math.min(this.pollMin + 1, this.pollOptionsCount));
+        this.set("pollMax", this.pollOptionsCount);
       }
     } else if (this.isNumber) {
       this.set("pollMax", this.siteSettings.poll_maximum_options);
@@ -226,11 +228,22 @@ export default Controller.extend(ModalFunctionality, {
   minNumOfOptionsValidation(isNumber, pollOptionsCount) {
     let options = { ok: true };
 
-    if (!isNumber && pollOptionsCount === 0) {
-      options = {
-        failed: true,
-        reason: I18n.t("poll.ui_builder.help.options_count"),
-      };
+    if (!isNumber) {
+      if (pollOptionsCount < 1) {
+        return EmberObject.create({
+          failed: true,
+          reason: I18n.t("poll.ui_builder.help.options_min_count"),
+        });
+      }
+
+      if (pollOptionsCount > this.siteSettings.poll_maximum_options) {
+        return EmberObject.create({
+          failed: true,
+          reason: I18n.t("poll.ui_builder.help.options_max_count", {
+            count: this.siteSettings.poll_maximum_options,
+          }),
+        });
+      }
     }
 
     return EmberObject.create(options);
@@ -246,69 +259,75 @@ export default Controller.extend(ModalFunctionality, {
     "pollOptionsCount",
     "isNumber",
     "pollMin",
-    "pollMax"
+    "pollMax",
+    "pollStep"
   )
   minMaxValueValidation(
     isMultiple,
     pollOptionsCount,
     isNumber,
     pollMin,
-    pollMax
+    pollMax,
+    pollStep
   ) {
     pollMin = parseInt(pollMin, 10) || 0;
     pollMax = parseInt(pollMax, 10) || 0;
+    pollStep = parseInt(pollStep, 10) || 0;
 
-    const fail = {
-      failed: true,
-      reason: I18n.t("poll.ui_builder.help.invalid_values"),
-    };
+    if (pollMin < 0) {
+      return EmberObject.create({
+        failed: true,
+        reason: I18n.t("poll.ui_builder.help.invalid_min_value"),
+      });
+    }
 
-    if (isMultiple) {
-      if (
-        pollMin > pollMax ||
-        pollMin < 0 ||
-        (pollOptionsCount > 0 && pollMax > pollOptionsCount)
-      ) {
-        return EmberObject.create(fail);
-      }
-    } else if (isNumber) {
-      if (pollMin >= pollMax) {
-        return EmberObject.create(fail);
-      }
+    if (pollMax < 0 || (isMultiple && pollMax > pollOptionsCount)) {
+      return EmberObject.create({
+        failed: true,
+        reason: I18n.t("poll.ui_builder.help.invalid_max_value"),
+      });
     }
 
-    return EmberObject.create({ ok: true });
-  },
+    if (pollMin > pollMax) {
+      return EmberObject.create({
+        failed: true,
+        reason: I18n.t("poll.ui_builder.help.invalid_values"),
+      });
+    }
 
-  @discourseComputed("isNumber", "pollStep")
-  minStepValueValidation(isNumber, pollStep) {
-    let options = { ok: true };
+    if (isNumber) {
+      if (pollStep < 1) {
+        return EmberObject.create({
+          failed: true,
+          reason: I18n.t("poll.ui_builder.help.min_step_value"),
+        });
+      }
 
-    if (isNumber && pollStep < 1) {
-      options = {
-        failed: true,
-        reason: I18n.t("poll.ui_builder.help.min_step_value"),
-      };
+      const optionsCount = (pollMax - pollMin + 1) / pollStep;
+
+      if (optionsCount < 1) {
+        return EmberObject.create({
+          failed: true,
+          reason: I18n.t("poll.ui_builder.help.options_min_count"),
+        });
+      }
+
+      if (optionsCount > this.siteSettings.poll_maximum_options) {
+        return EmberObject.create({
+          failed: true,
+          reason: I18n.t("poll.ui_builder.help.options_max_count", {
+            count: this.siteSettings.poll_maximum_options,
+          }),
+        });
+      }
     }
 
-    return EmberObject.create(options);
+    return EmberObject.create({ ok: true });
   },
 
-  @discourseComputed(
-    "minMaxValueValidation",
-    "minStepValueValidation",
-    "minNumOfOptionsValidation"
-  )
-  disableInsert(
-    minMaxValueValidation,
-    minStepValueValidation,
-    minNumOfOptionsValidation
-  ) {
-    return (
-      !minMaxValueValidation.ok ||
-      !minStepValueValidation.ok ||
-      !minNumOfOptionsValidation.ok
-    );
+  @discourseComputed("minMaxValueValidation", "minNumOfOptionsValidation")
+  disableInsert(minMaxValueValidation, minNumOfOptionsValidation) {
+    return !minMaxValueValidation.ok || !minNumOfOptionsValidation.ok;
   },
 
   _comboboxOptions(startIndex, endIndex) {
diff --git a/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs b/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs
index df14ba4..0f2f447 100644
--- a/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs
+++ b/plugins/poll/assets/javascripts/discourse/templates/modal/poll-ui-builder.hbs
@@ -53,7 +53,8 @@
         {{input type="number"
                 value=pollMin
                 valueProperty="value"
-                class="poll-options-min"}}
+                class="poll-options-min"
+                min=1}}
       </div>
 
       <div class="input-group poll-number">
@@ -61,7 +62,8 @@
         {{input type="number"
                 value=pollMax
                 valueProperty="value"
-                class="poll-options-max"}}
+                class="poll-options-max"
+                min=1}}
       </div>
 
       {{#if isNumber}}
@@ -73,7 +75,6 @@
                   min="1"
                   class="poll-options-step"}}
         </div>

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

GitHub sha: 6c5d6dd3

This commit appears in #12745 which was approved by jjaffeux and ZogStriP. It was merged by nbianca.