diff --git a/assets/javascripts/discourse/components/param-input.hbs b/assets/javascripts/discourse/components/param-input.hbs new file mode 100644 index 0000000..70590bb --- /dev/null +++ b/assets/javascripts/discourse/components/param-input.hbs @@ -0,0 +1,55 @@ +
+ {{#if (eq this.type "boolean")}} + {{#if @info.nullable}} + + {{else}} + + {{/if}} + {{@info.identifier}} + + {{else if (eq this.type "int")}} + + {{@info.identifier}} + + {{else if (eq this.type "string")}} + + {{@info.identifier}} + + {{else if (eq this.type "user_id")}} + + {{@info.identifier}} + + {{else if (eq this.type "user_list")}} + + {{@info.identifier}} + + {{else}} + + {{@info.identifier}} + {{/if}} +
diff --git a/assets/javascripts/discourse/components/param-input.js b/assets/javascripts/discourse/components/param-input.js index 31f7768..f66c321 100644 --- a/assets/javascripts/discourse/components/param-input.js +++ b/assets/javascripts/discourse/components/param-input.js @@ -1,10 +1,11 @@ -import Component from "@ember/component"; +import Component from "@glimmer/component"; import I18n from "I18n"; -import discourseComputed from "discourse-common/utils/decorators"; import Category from "discourse/models/category"; import { dasherize } from "@ember/string"; import { isEmpty } from "@ember/utils"; -import { computed } from "@ember/object"; +import { action } from "@ember/object"; +import { tracked } from "@glimmer/tracking"; +import { inject as service } from "@ember/service"; const layoutMap = { int: "int", @@ -26,58 +27,73 @@ const layoutMap = { user_list: "user_list", }; -function allowsInputTypeTime() { - try { - const inp = document.createElement("input"); - inp.attributes.type = "time"; - inp.attributes.type = "date"; - return true; - } catch (e) { - return false; - } -} +export default class ParamInput extends Component { + @service site; -export default Component.extend({ - classNameBindings: ["valid:valid:invalid", ":param"], + @tracked value; + @tracked boolValue; + @tracked nullableBoolValue; - boolTypes: [ + boolTypes = [ { name: I18n.t("explorer.types.bool.true"), id: "Y" }, { name: I18n.t("explorer.types.bool.false"), id: "N" }, { name: I18n.t("explorer.types.bool.null_"), id: "#null" }, - ], - initialValues: null, + ]; - init() { - this._super(...arguments); + constructor() { + super(...arguments); - if (this.initialValues && this.info.identifier in this.initialValues) { - this.set("value", this.initialValues[this.info.identifier]); + const identifier = this.args.info.identifier; + const initialValues = this.args.initialValues; + + // access parsed params if present to update values to previously ran values + if (initialValues && identifier in initialValues) { + const initialValue = initialValues[identifier]; + if (this.type === "boolean") { + if (this.args.info.nullable) { + this.nullableBoolValue = initialValue; + } else { + this.boolValue = initialValue !== "false"; + } + } else { + this.value = + this.args.info.type === "category_id" + ? this.dasherizeCategoryId(initialValue) + : initialValue; + } + } else { + // if no parsed params then get and set default values + const params = this.args.params; + this.value = + this.args.info.type === "category_id" + ? this.dasherizeCategoryId(params[identifier]) + : params[identifier]; + this.boolValue = params[identifier] !== "false"; + this.nullableBoolValue = params[identifier]; } - }, + } - value: computed("params", "info.identifier", { - get() { - return this.params[this.get("info.identifier")]; - }, - set(key, value) { - this.params[this.get("info.identifier")] = value?.toString(); - return value; - }, - }), + get type() { + const type = this.args.info.type; + if ((type === "time" || type === "date") && !allowsInputTypeTime()) { + return "string"; + } + return layoutMap[type] || "generic"; + } - valueBool: computed("params", "info.identifier", { - get() { - return this.params[this.get("info.identifier")] !== "false"; - }, - set(key, value) { - value = !!value; - this.params[this.get("info.identifier")] = value.toString(); - return value; - }, - }), + get valid() { + const nullable = this.args.info.nullable; + // intentionally use 'this.args' here instead of 'this.type' + // to get the original key instead of the translated value from the layoutMap + const type = this.args.info.type; + let value; + + if (type === "boolean") { + value = nullable ? this.nullableBoolValue : this.boolValue; + } else { + value = this.value; + } - @discourseComputed("value", "info.type", "info.nullable") - valid(value, type, nullable) { if (isEmpty(value)) { return nullable; } @@ -104,10 +120,6 @@ export default Component.extend({ case "post_id": return isPositiveInt || /\d+\/\d+(\?u=.*)?$/.test(value); case "category_id": - if (!isPositiveInt && value !== dasherize(value)) { - this.set("value", dasherize(value)); - } - if (isPositiveInt) { return !!this.site.categories.find((c) => c.id === intVal); } else if (/\//.test(value)) { @@ -132,21 +144,55 @@ export default Component.extend({ } } return true; - }, + } - @discourseComputed("info.type") - layoutType(type) { - if ((type === "time" || type === "date") && !allowsInputTypeTime()) { - return "string"; + dasherizeCategoryId(value) { + const isPositiveInt = /^\d+$/.test(value); + if (!isPositiveInt && value !== dasherize(value)) { + return dasherize(value); } - if (layoutMap[type]) { - return layoutMap[type]; - } - return "generic"; - }, + return value; + } - @discourseComputed("layoutType") - layoutName(layoutType) { - return `admin/components/q-params/${layoutType}`; - }, -}); + @action + updateValue(input) { + // handle selectKit inputs as well as traditional inputs + const value = input.target ? input.target.value : input; + if (value.length) { + this.value = + this.args.info.type === "category_id" + ? this.dasherizeCategoryId(value.toString()) + : value.toString(); + } else { + this.value = value; + } + + this.args.updateParams(this.args.info.identifier, this.value); + } + + @action + updateBoolValue(input) { + this.boolValue = input.target.checked; + this.args.updateParams( + this.args.info.identifier, + this.boolValue.toString() + ); + } + + @action + updateNullableBoolValue(input) { + this.nullableBoolValue = input; + this.args.updateParams(this.args.info.identifier, this.nullableBoolValue); + } +} + +function allowsInputTypeTime() { + try { + const input = document.createElement("input"); + input.attributes.type = "time"; + input.attributes.type = "date"; + return true; + } catch (e) { + return false; + } +} diff --git a/assets/javascripts/discourse/components/param-inputs-wrapper.hbs b/assets/javascripts/discourse/components/param-inputs-wrapper.hbs new file mode 100644 index 0000000..77ce00d --- /dev/null +++ b/assets/javascripts/discourse/components/param-inputs-wrapper.hbs @@ -0,0 +1,12 @@ +{{#if @hasParams}} +
+ {{#each @paramInfo as |pinfo|}} + + {{/each}} +
+{{/if}} diff --git a/assets/javascripts/discourse/controllers/admin-plugins-explorer.js b/assets/javascripts/discourse/controllers/admin-plugins-explorer.js index 527347e..9e806f6 100644 --- a/assets/javascripts/discourse/controllers/admin-plugins-explorer.js +++ b/assets/javascripts/discourse/controllers/admin-plugins-explorer.js @@ -312,6 +312,12 @@ export default Controller.extend({ }); }, + // This is necessary with glimmer's one way data stream to get the child's + // changes of 'params' to bubble up. + updateParams(identifier, value) { + this.selectedItem.set(`params.${identifier}`, value); + }, + run() { if (this.get("selectedItem.dirty")) { return; @@ -325,6 +331,7 @@ export default Controller.extend({ showResults: false, params: JSON.stringify(this.selectedItem.params), }); + ajax( "/admin/plugins/explorer/queries/" + this.get("selectedItem.id") + diff --git a/assets/javascripts/discourse/templates/admin/components/q-params/boolean.hbs b/assets/javascripts/discourse/templates/admin/components/q-params/boolean.hbs deleted file mode 100644 index f375e36..0000000 --- a/assets/javascripts/discourse/templates/admin/components/q-params/boolean.hbs +++ /dev/null @@ -1,12 +0,0 @@ -{{#if info.nullable}} - {{combo-box - valueAttribute="id" - value=value - nameProperty="name" - content=boolTypes - }} -{{else}} - {{input type="checkbox" checked=valueBool}} -{{/if}} - -{{info.identifier}} diff --git a/assets/javascripts/discourse/templates/admin/components/q-params/generic.hbs b/assets/javascripts/discourse/templates/admin/components/q-params/generic.hbs deleted file mode 100644 index 2b0fd48..0000000 --- a/assets/javascripts/discourse/templates/admin/components/q-params/generic.hbs +++ /dev/null @@ -1,2 +0,0 @@ -{{text-field value=value}} -{{info.identifier}} diff --git a/assets/javascripts/discourse/templates/admin/components/q-params/int.hbs b/assets/javascripts/discourse/templates/admin/components/q-params/int.hbs deleted file mode 100644 index efb887d..0000000 --- a/assets/javascripts/discourse/templates/admin/components/q-params/int.hbs +++ /dev/null @@ -1,2 +0,0 @@ -{{input type="number" value=value}} -{{info.identifier}} diff --git a/assets/javascripts/discourse/templates/admin/components/q-params/string.hbs b/assets/javascripts/discourse/templates/admin/components/q-params/string.hbs deleted file mode 100644 index f1c5fdc..0000000 --- a/assets/javascripts/discourse/templates/admin/components/q-params/string.hbs +++ /dev/null @@ -1,2 +0,0 @@ -{{text-field value=value type="text"}} -{{info.identifier}} diff --git a/assets/javascripts/discourse/templates/admin/components/q-params/user_id.hbs b/assets/javascripts/discourse/templates/admin/components/q-params/user_id.hbs deleted file mode 100644 index efc8f52..0000000 --- a/assets/javascripts/discourse/templates/admin/components/q-params/user_id.hbs +++ /dev/null @@ -1,7 +0,0 @@ -{{email-group-user-chooser - value=value - options=(hash maximum=1) - onChange=(action (mut value)) -}} - -{{info.identifier}} diff --git a/assets/javascripts/discourse/templates/admin/components/q-params/user_list.hbs b/assets/javascripts/discourse/templates/admin/components/q-params/user_list.hbs deleted file mode 100644 index 141edc6..0000000 --- a/assets/javascripts/discourse/templates/admin/components/q-params/user_list.hbs +++ /dev/null @@ -1,2 +0,0 @@ -{{email-group-user-chooser value=value onChange=(action (mut value))}} -{{info.identifier}} diff --git a/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs b/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs index 503a527..11569a8 100644 --- a/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs +++ b/assets/javascripts/discourse/templates/admin/plugins-explorer.hbs @@ -212,17 +212,13 @@
- {{#if selectedItem.hasParams}} -
- {{#each selectedItem.param_info as |pinfo|}} - {{param-input - params=selectedItem.params - initialValues=parsedParams - info=pinfo - }} - {{/each}} -
- {{/if}} + {{#if runDisabled}} {{#if saveDisabled}} diff --git a/assets/javascripts/discourse/templates/group-reports-show.hbs b/assets/javascripts/discourse/templates/group-reports-show.hbs index 4d7f249..b700c4f 100644 --- a/assets/javascripts/discourse/templates/group-reports-show.hbs +++ b/assets/javascripts/discourse/templates/group-reports-show.hbs @@ -3,13 +3,12 @@

{{model.description}}

- {{#if hasParams}} -
- {{#each model.param_info as |pinfo|}} - {{param-input params=model.params info=pinfo}} - {{/each}} -
- {{/if}} + {{d-button action=(action "run")