FIX: Form validation bugs, new modal api, glimmer (#182)
This commit is contained in:
parent
bc81d30dc8
commit
30ac835e1d
|
@ -5,14 +5,14 @@
|
||||||
@icon="pencil-alt"
|
@icon="pencil-alt"
|
||||||
@title="chat_integration.edit_channel"
|
@title="chat_integration.edit_channel"
|
||||||
@label="chat_integration.edit_channel"
|
@label="chat_integration.edit_channel"
|
||||||
@action={{action @editChannel @channel}}
|
@action={{fn @editChannel @channel}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DButton
|
<DButton
|
||||||
@icon="rocket"
|
@icon="rocket"
|
||||||
@title="chat_integration.test_channel"
|
@title="chat_integration.test_channel"
|
||||||
@label="chat_integration.test_channel"
|
@label="chat_integration.test_channel"
|
||||||
@action={{action @test @channel}}
|
@action={{fn @test @channel}}
|
||||||
@class="btn-chat-test"
|
@class="btn-chat-test"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@
|
||||||
@icon="trash-alt"
|
@icon="trash-alt"
|
||||||
@title="chat_integration.delete_channel"
|
@title="chat_integration.delete_channel"
|
||||||
@label="chat_integration.delete_channel"
|
@label="chat_integration.delete_channel"
|
||||||
@action={{action this.deleteChannel @channel}}
|
@action={{fn this.deleteChannel @channel}}
|
||||||
@class="cancel delete-channel"
|
@class="cancel delete-channel"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
<DButton
|
<DButton
|
||||||
@class="delete btn-danger"
|
@class="delete btn-danger"
|
||||||
@icon="exclamation-triangle"
|
@icon="exclamation-triangle"
|
||||||
@action={{action @showError @channel}}
|
@action={{fn @showError @channel}}
|
||||||
/>
|
/>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@
|
||||||
{{#each @channel.rules as |rule|}}
|
{{#each @channel.rules as |rule|}}
|
||||||
<RuleRow
|
<RuleRow
|
||||||
@rule={{rule}}
|
@rule={{rule}}
|
||||||
@edit={{action @editRuleWithChannel rule @channel}}
|
@edit={{fn @editRuleWithChannel rule @channel}}
|
||||||
@refresh={{@refresh}}
|
@refresh={{@refresh}}
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
@ -71,7 +71,7 @@
|
||||||
@icon="plus"
|
@icon="plus"
|
||||||
@title="chat_integration.create_rule"
|
@title="chat_integration.create_rule"
|
||||||
@label="chat_integration.create_rule"
|
@label="chat_integration.create_rule"
|
||||||
@action={{action @createRule @channel}}
|
@action={{fn @createRule @channel}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
{{i18n
|
{{i18n
|
||||||
(concat
|
(concat
|
||||||
"chat_integration.provider."
|
"chat_integration.provider."
|
||||||
@model.channel.provider
|
@channel.provider
|
||||||
".param."
|
".param."
|
||||||
@param.key
|
@param.key
|
||||||
".title"
|
".title"
|
||||||
|
@ -13,14 +13,14 @@
|
||||||
</label>
|
</label>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<Input
|
<input
|
||||||
name={{concat "param-" @param.key}}
|
{{on "input" this.updateValue}}
|
||||||
@value={{this.inputValue}}
|
value={{get @channel.data @param.key}}
|
||||||
{{on "change" this.updateValue}}
|
type="text"
|
||||||
|
name="param-{{@param.key}}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InputTip @validation={{this.validate}} />
|
<InputTip @validation={{this.validation}} />
|
||||||
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
||||||
{{i18n
|
{{i18n
|
||||||
(concat
|
(concat
|
||||||
"chat_integration.provider."
|
"chat_integration.provider."
|
||||||
@model.channel.provider
|
@channel.provider
|
||||||
".param."
|
".param."
|
||||||
@param.key
|
@param.key
|
||||||
".help"
|
".help"
|
||||||
|
|
|
@ -1,51 +1,34 @@
|
||||||
import Component from "@glimmer/component";
|
import Component from "@glimmer/component";
|
||||||
import { tracked } from "@glimmer/tracking";
|
import { action } from "@ember/object";
|
||||||
import EmberObject, { action } from "@ember/object";
|
|
||||||
import I18n from "I18n";
|
import I18n from "I18n";
|
||||||
|
|
||||||
export default class ChannelParamRow extends Component {
|
export default class ChannelParamRow extends Component {
|
||||||
@tracked inputValue = this.args.model.channel.data[this.args.param.key] || "";
|
get validation() {
|
||||||
|
const value = this.args.channel.get(`data.${this.args.param.key}`);
|
||||||
|
|
||||||
get validate() {
|
if (!value?.trim()) {
|
||||||
const parameter = this.args.param;
|
return { failed: true };
|
||||||
const regString = parameter.regex;
|
} else if (!this.args.param.regex) {
|
||||||
const regex = new RegExp(regString);
|
return { ok: true };
|
||||||
|
} else if (new RegExp(this.args.param.regex).test(value)) {
|
||||||
if (this.inputValue === "") {
|
return {
|
||||||
// Fail silently if field blank
|
|
||||||
this.args.isValidParams(false);
|
|
||||||
return EmberObject.create({
|
|
||||||
failed: true,
|
|
||||||
});
|
|
||||||
} else if (!regString) {
|
|
||||||
// Pass silently if no regex available for provider
|
|
||||||
this.args.isValidParams(true);
|
|
||||||
return EmberObject.create({
|
|
||||||
ok: true,
|
|
||||||
});
|
|
||||||
} else if (regex.test(this.inputValue)) {
|
|
||||||
// Test against regex
|
|
||||||
this.args.isValidParams(true);
|
|
||||||
return EmberObject.create({
|
|
||||||
ok: true,
|
ok: true,
|
||||||
reason: I18n.t(
|
reason: I18n.t(
|
||||||
"chat_integration.edit_channel_modal.channel_validation.ok"
|
"chat_integration.edit_channel_modal.channel_validation.ok"
|
||||||
),
|
),
|
||||||
});
|
};
|
||||||
} else {
|
} else {
|
||||||
// Failed regex
|
return {
|
||||||
this.args.isValidParams(false);
|
|
||||||
return EmberObject.create({
|
|
||||||
failed: true,
|
failed: true,
|
||||||
reason: I18n.t(
|
reason: I18n.t(
|
||||||
"chat_integration.edit_channel_modal.channel_validation.fail"
|
"chat_integration.edit_channel_modal.channel_validation.fail"
|
||||||
),
|
),
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
updateValue(event) {
|
updateValue(event) {
|
||||||
this.args.model.channel.data[this.args.param.key] = event.target.value;
|
this.args.channel.set(`data.${this.args.param.key}`, event.target.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<DModal @closeModal={{@closeModal}} id="chat_integration_error_modal">
|
||||||
|
<h4>{{i18n @model.error_key}}</h4>
|
||||||
|
<pre>{{@model.error_info}}</pre>
|
||||||
|
</DModal>
|
|
@ -0,0 +1,54 @@
|
||||||
|
<DModal
|
||||||
|
{{on "submit" this.save}}
|
||||||
|
@title={{i18n "chat_integration.edit_channel_modal.title"}}
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@tagName="form"
|
||||||
|
id="chat-integration-edit-channel-modal"
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="provider">
|
||||||
|
{{i18n "chat_integration.edit_channel_modal.provider"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{i18n
|
||||||
|
(concat
|
||||||
|
"chat_integration.provider." @model.channel.provider ".title"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{#each @model.provider.channel_parameters as |param|}}
|
||||||
|
<ChannelParamRow @param={{param}} @channel={{@model.channel}} />
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</:body>
|
||||||
|
|
||||||
|
<:footer>
|
||||||
|
<DButton
|
||||||
|
@action={{this.save}}
|
||||||
|
@label="chat_integration.edit_channel_modal.save"
|
||||||
|
@disabled={{not this.validParams}}
|
||||||
|
type="submit"
|
||||||
|
id="save-channel"
|
||||||
|
class="btn-primary btn-large"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@action={{@closeModal}}
|
||||||
|
@label="chat_integration.edit_channel_modal.cancel"
|
||||||
|
class="btn-large"
|
||||||
|
/>
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
|
@ -0,0 +1,31 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
export default class EditChannel extends Component {
|
||||||
|
get validParams() {
|
||||||
|
return this.args.model.provider.channel_parameters.every((param) => {
|
||||||
|
const value = this.args.model.channel.get(`data.${param.key}`);
|
||||||
|
|
||||||
|
if (!value?.trim()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!param.regex) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new RegExp(param.regex).test(value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@action
|
||||||
|
async save() {
|
||||||
|
try {
|
||||||
|
await this.args.model.channel.save();
|
||||||
|
this.args.closeModal();
|
||||||
|
} catch (e) {
|
||||||
|
popupAjaxError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,201 @@
|
||||||
|
<DModal
|
||||||
|
{{on "submit" this.save}}
|
||||||
|
@title={{i18n "chat_integration.edit_rule_modal.title"}}
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@tagName="form"
|
||||||
|
id="chat-integration-edit-rule_modal"
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="provider">
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.provider"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{i18n
|
||||||
|
(concat
|
||||||
|
"chat_integration.provider." @model.channel.provider ".title"
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="channel">
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.channel"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ChannelData
|
||||||
|
@provider={{@model.provider}}
|
||||||
|
@channel={{@model.channel}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="filter">
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.type"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ComboBox
|
||||||
|
@name="type"
|
||||||
|
@content={{@model.rule.available_types}}
|
||||||
|
@value={{@model.rule.type}}
|
||||||
|
@onChange={{fn (mut @model.rule.type)}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.instructions.type"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="filter">
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.filter"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ComboBox
|
||||||
|
@name="filter"
|
||||||
|
@content={{@model.rule.available_filters}}
|
||||||
|
@value={{@model.rule.filter}}
|
||||||
|
@onChange={{fn (mut @model.rule.filter)}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.instructions.filter"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{{#if (eq @model.rule.type "normal")}}
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="category">
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.category"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<CategoryChooser
|
||||||
|
@name="category"
|
||||||
|
@options={{hash none="chat_integration.all_categories"}}
|
||||||
|
@value={{@model.rule.category_id}}
|
||||||
|
@onChange={{fn (mut @model.rule.category_id)}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
{{i18n
|
||||||
|
"chat_integration.edit_rule_modal.instructions.category"
|
||||||
|
}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{else}}
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="group">
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.group"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ComboBox
|
||||||
|
@content={{@model.groups}}
|
||||||
|
@valueProperty="id"
|
||||||
|
@value={{@model.rule.group_id}}
|
||||||
|
@onChange={{fn (mut @model.rule.group_id)}}
|
||||||
|
@options={{hash none="chat_integration.choose_group"}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.instructions.group"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if this.siteSettings.tagging_enabled}}
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="tags">
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.tags"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<TagChooser
|
||||||
|
@placeholderKey="chat_integration.all_tags"
|
||||||
|
@name="tags"
|
||||||
|
@tags={{@model.rule.tags}}
|
||||||
|
@everyTag="true"
|
||||||
|
@onChange={{fn (mut @model.rule.tags)}}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class="chat-instructions">
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<label>
|
||||||
|
{{i18n "chat_integration.edit_rule_modal.instructions.tags"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{{/if}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</:body>
|
||||||
|
|
||||||
|
<:footer>
|
||||||
|
<DButton
|
||||||
|
@action={{fn this.save @model.rule}}
|
||||||
|
@label="chat_integration.edit_rule_modal.save"
|
||||||
|
type="submit"
|
||||||
|
id="save-rule"
|
||||||
|
class="btn-primary btn-large"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<DButton
|
||||||
|
@label="chat_integration.edit_rule_modal.cancel"
|
||||||
|
@action={{@closeModal}}
|
||||||
|
class="btn-large"
|
||||||
|
/>
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
|
@ -0,0 +1,18 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { inject as service } from "@ember/service";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
|
export default class EditRule extends Component {
|
||||||
|
@service siteSettings;
|
||||||
|
|
||||||
|
@action
|
||||||
|
async save(rule) {
|
||||||
|
try {
|
||||||
|
await rule.save();
|
||||||
|
this.args.closeModal();
|
||||||
|
} catch (e) {
|
||||||
|
popupAjaxError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<DModal
|
||||||
|
{{on "submit" this.send}}
|
||||||
|
@title={{i18n "chat_integration.test_modal.title"}}
|
||||||
|
@closeModal={{@closeModal}}
|
||||||
|
@flash={{this.flash}}
|
||||||
|
@flashType="success"
|
||||||
|
@tagName="form"
|
||||||
|
id="chat_integration_test_modal"
|
||||||
|
>
|
||||||
|
<:body>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr class="input">
|
||||||
|
<td class="label">
|
||||||
|
<label for="channel">
|
||||||
|
{{i18n "chat_integration.test_modal.topic"}}
|
||||||
|
</label>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<ChooseTopic @selectedTopicId={{this.topicId}} />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</:body>
|
||||||
|
|
||||||
|
<:footer>
|
||||||
|
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
||||||
|
<DButton
|
||||||
|
@action={{this.send}}
|
||||||
|
@label="chat_integration.test_modal.send"
|
||||||
|
@disabled={{not this.topicId}}
|
||||||
|
type="submit"
|
||||||
|
id="send-test"
|
||||||
|
class="btn-primary btn-large"
|
||||||
|
/>
|
||||||
|
<DButton
|
||||||
|
@action={{@closeModal}}
|
||||||
|
@label="chat_integration.test_modal.close"
|
||||||
|
class="btn-large"
|
||||||
|
/>
|
||||||
|
</ConditionalLoadingSpinner>
|
||||||
|
</:footer>
|
||||||
|
</DModal>
|
|
@ -0,0 +1,32 @@
|
||||||
|
import Component from "@glimmer/component";
|
||||||
|
import { tracked } from "@glimmer/tracking";
|
||||||
|
import { action } from "@ember/object";
|
||||||
|
import { ajax } from "discourse/lib/ajax";
|
||||||
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export default class TestIntegration extends Component {
|
||||||
|
@tracked loading = false;
|
||||||
|
@tracked flash;
|
||||||
|
@tracked topicId;
|
||||||
|
|
||||||
|
@action
|
||||||
|
async send() {
|
||||||
|
this.loading = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await ajax("/admin/plugins/chat-integration/test", {
|
||||||
|
data: {
|
||||||
|
channel_id: this.args.model.channel.id,
|
||||||
|
topic_id: this.topicId,
|
||||||
|
},
|
||||||
|
type: "POST",
|
||||||
|
});
|
||||||
|
|
||||||
|
this.loading = false;
|
||||||
|
this.flash = I18n.t("chat_integration.test_modal.success");
|
||||||
|
} catch (e) {
|
||||||
|
popupAjaxError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@
|
||||||
@class="delete"
|
@class="delete"
|
||||||
@icon="far-trash-alt"
|
@icon="far-trash-alt"
|
||||||
@title="chat_integration.rule_table.delete_rule"
|
@title="chat_integration.rule_table.delete_rule"
|
||||||
@action={{action this.delete}}
|
@action={{this.delete}}
|
||||||
@actionParam={{@rule}}
|
@actionParam={{@rule}}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -2,6 +2,7 @@ import Component from "@glimmer/component";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { inject as service } from "@ember/service";
|
import { inject as service } from "@ember/service";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
|
|
||||||
export default class RuleRow extends Component {
|
export default class RuleRow extends Component {
|
||||||
@service siteSettings;
|
@service siteSettings;
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,19 @@
|
||||||
import { tracked } from "@glimmer/tracking";
|
|
||||||
import Controller from "@ember/controller";
|
import Controller from "@ember/controller";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import showModal from "discourse/lib/show-modal";
|
import { inject as service } from "@ember/service";
|
||||||
|
import ChannelErrorModal from "../components/modal/channel-error";
|
||||||
|
import EditChannelModal from "../components/modal/edit-channel";
|
||||||
|
import EditRuleModal from "../components/modal/edit-rule";
|
||||||
|
import TestModal from "../components/modal/test-integration";
|
||||||
|
|
||||||
const MODALS = {
|
export default class AdminPluginsChatIntegrationProvider extends Controller {
|
||||||
editChannel: "admin-plugins-chat-integration-edit-channel",
|
@service modal;
|
||||||
testChannel: "admin-plugins-chat-integration-test",
|
@service store;
|
||||||
editRule: "admin-plugins-chat-integration-edit-rule",
|
|
||||||
channelError: "admin-plugins-chat-integration-channel-error",
|
|
||||||
};
|
|
||||||
|
|
||||||
export default class AdminPluginsChatIntegrationEditRule extends Controller {
|
|
||||||
@tracked modalShowing = false;
|
|
||||||
|
|
||||||
get anyErrors() {
|
get anyErrors() {
|
||||||
const channels = this.model.channels;
|
|
||||||
let anyErrors = false;
|
let anyErrors = false;
|
||||||
|
|
||||||
channels.forEach((channel) => {
|
this.model.channels.forEach((channel) => {
|
||||||
if (channel.error_key) {
|
if (channel.error_key) {
|
||||||
anyErrors = true;
|
anyErrors = true;
|
||||||
}
|
}
|
||||||
|
@ -26,77 +22,67 @@ export default class AdminPluginsChatIntegrationEditRule extends Controller {
|
||||||
return anyErrors;
|
return anyErrors;
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerModal(model, modal) {
|
async triggerModal(modal, model) {
|
||||||
this.modalShowing = true;
|
await this.modal.show(modal, {
|
||||||
|
model: {
|
||||||
showModal(modal, {
|
...model,
|
||||||
model,
|
admin: true,
|
||||||
admin: true,
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
createChannel() {
|
createChannel() {
|
||||||
return this.triggerModal(
|
return this.triggerModal(EditChannelModal, {
|
||||||
{
|
channel: this.store.createRecord("channel", {
|
||||||
channel: this.store.createRecord("channel", {
|
provider: this.model.provider.id,
|
||||||
provider: this.model.provider.id,
|
data: {},
|
||||||
data: {},
|
}),
|
||||||
}),
|
provider: this.model.provider,
|
||||||
provider: this.model.provider,
|
});
|
||||||
},
|
|
||||||
MODALS.editChannel
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
editChannel(channel) {
|
editChannel(channel) {
|
||||||
return this.triggerModal(
|
return this.triggerModal(EditChannelModal, {
|
||||||
{
|
channel,
|
||||||
channel,
|
provider: this.model.provider,
|
||||||
provider: this.model.provider,
|
});
|
||||||
},
|
|
||||||
MODALS.editChannel
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
testChannel(channel) {
|
testChannel(channel) {
|
||||||
return this.triggerModal({ channel }, MODALS.testChannel);
|
return this.triggerModal(TestModal, { channel });
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
createRule(channel) {
|
createRule(channel) {
|
||||||
return this.triggerModal(
|
return this.triggerModal(EditRuleModal, {
|
||||||
{
|
rule: this.store.createRecord("rule", {
|
||||||
rule: this.store.createRecord("rule", {
|
channel_id: channel.id,
|
||||||
channel_id: channel.id,
|
|
||||||
channel,
|
|
||||||
}),
|
|
||||||
channel,
|
channel,
|
||||||
provider: this.model.provider,
|
}),
|
||||||
groups: this.model.groups,
|
channel,
|
||||||
},
|
provider: this.model.provider,
|
||||||
MODALS.editRule
|
groups: this.model.groups,
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
editRuleWithChannel(rule, channel) {
|
editRuleWithChannel(rule, channel) {
|
||||||
return this.triggerModal(
|
return this.triggerModal(EditRuleModal, {
|
||||||
{
|
rule,
|
||||||
rule,
|
channel,
|
||||||
channel,
|
provider: this.model.provider,
|
||||||
provider: this.model.provider,
|
groups: this.model.groups,
|
||||||
groups: this.model.groups,
|
});
|
||||||
},
|
|
||||||
MODALS.editRule
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
showError(channel) {
|
showError(channel) {
|
||||||
return this.triggerModal({ channel }, MODALS.channelError);
|
return this.triggerModal(ChannelErrorModal, { channel });
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|
|
@ -1,42 +0,0 @@
|
||||||
import { tracked } from "@glimmer/tracking";
|
|
||||||
import Controller from "@ember/controller";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
|
||||||
|
|
||||||
export default class AdminPluginsChatIntegrationEditChannel extends Controller.extend(
|
|
||||||
ModalFunctionality
|
|
||||||
) {
|
|
||||||
@tracked validParams = false;
|
|
||||||
|
|
||||||
@action
|
|
||||||
isValidParams(validity) {
|
|
||||||
return (this.validParams = validity);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
handleKeyUp(e) {
|
|
||||||
if (e.code === "Enter" && this.validParams) {
|
|
||||||
this.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
cancel() {
|
|
||||||
this.send("closeModal");
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
save() {
|
|
||||||
if (!this.validParams) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.model.channel
|
|
||||||
.save()
|
|
||||||
.then(() => {
|
|
||||||
this.send("closeModal");
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
import { tracked } from "@glimmer/tracking";
|
|
||||||
import Controller from "@ember/controller";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { inject as service } from "@ember/service";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
|
||||||
|
|
||||||
export default class AdminPluginsChatIntegrationEditRule extends Controller.extend(
|
|
||||||
ModalFunctionality
|
|
||||||
) {
|
|
||||||
@service siteSettings;
|
|
||||||
@tracked saveDisabled = false;
|
|
||||||
|
|
||||||
get showCategory() {
|
|
||||||
return this.model.rule.type === "normal";
|
|
||||||
}
|
|
||||||
|
|
||||||
get currentRuleType() {
|
|
||||||
return this.model.rule.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
save(rule) {
|
|
||||||
if (this.saveDisabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
rule
|
|
||||||
.save()
|
|
||||||
.then(() => this.send("closeModal"))
|
|
||||||
.catch(popupAjaxError);
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
handleKeyUp(e) {
|
|
||||||
if (e.code === "Enter") {
|
|
||||||
this.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
onChangeRuleType(type) {
|
|
||||||
this.model.rule.type = type;
|
|
||||||
this.currentRuleType = type;
|
|
||||||
if (type !== "normal") {
|
|
||||||
this.showCategory = false;
|
|
||||||
} else {
|
|
||||||
this.showCategory = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
import { tracked } from "@glimmer/tracking";
|
|
||||||
import Controller from "@ember/controller";
|
|
||||||
import { action } from "@ember/object";
|
|
||||||
import { not } from "@ember/object/computed";
|
|
||||||
import { ajax } from "discourse/lib/ajax";
|
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
|
||||||
import ModalFunctionality from "discourse/mixins/modal-functionality";
|
|
||||||
import I18n from "I18n";
|
|
||||||
|
|
||||||
export default class AdminPluginsChatIntegrationTest extends Controller.extend(
|
|
||||||
ModalFunctionality
|
|
||||||
) {
|
|
||||||
@tracked loading = false;
|
|
||||||
@not("model.topic_id") sendDisabled;
|
|
||||||
|
|
||||||
@action
|
|
||||||
handleKeyUp(e) {
|
|
||||||
if (e.code === "Enter" && !this.sendDisabled) {
|
|
||||||
this.send();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
send() {
|
|
||||||
if (this.sendDisabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.loading = true;
|
|
||||||
|
|
||||||
ajax("/admin/plugins/chat-integration/test", {
|
|
||||||
data: {
|
|
||||||
channel_id: this.model.channel.id,
|
|
||||||
topic_id: this.model.topic_id,
|
|
||||||
},
|
|
||||||
type: "POST",
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
this.loading = false;
|
|
||||||
this.flash(I18n.t("chat_integration.test_modal.success"), "success");
|
|
||||||
})
|
|
||||||
.catch(popupAjaxError);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +1,38 @@
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import RSVP from "rsvp";
|
|
||||||
import Group from "discourse/models/group";
|
import Group from "discourse/models/group";
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default class AdminPluginsChatIntegrationProvider extends DiscourseRoute {
|
export default class AdminPluginsChatIntegrationProvider extends DiscourseRoute {
|
||||||
model(params) {
|
async model(params) {
|
||||||
return RSVP.hash({
|
const [channels, provider, groups] = await Promise.all([
|
||||||
channels: this.store.findAll("channel", { provider: params.provider }),
|
this.store.findAll("channel", { provider: params.provider }),
|
||||||
provider: this.modelFor("admin-plugins-chat-integration").findBy(
|
this.modelFor("admin-plugins-chat-integration").findBy(
|
||||||
"id",
|
"id",
|
||||||
params.provider
|
params.provider
|
||||||
),
|
),
|
||||||
groups: Group.findAll(),
|
Group.findAll(),
|
||||||
}).then((value) => {
|
]);
|
||||||
value.channels.forEach((channel) => {
|
|
||||||
channel.set(
|
|
||||||
"rules",
|
|
||||||
channel.rules.map((rule) => {
|
|
||||||
rule = this.store.createRecord("rule", rule);
|
|
||||||
rule.set("channel", channel);
|
|
||||||
return rule;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return value;
|
channels.forEach((channel) => {
|
||||||
|
channel.set(
|
||||||
|
"rules",
|
||||||
|
channel.rules.map((rule) => {
|
||||||
|
rule = this.store.createRecord("rule", rule);
|
||||||
|
rule.set("channel", channel);
|
||||||
|
return rule;
|
||||||
|
})
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
channels,
|
||||||
|
provider,
|
||||||
|
groups,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
serialize(model) {
|
serialize(model) {
|
||||||
return { provider: model["provider"].get("id") };
|
return { provider: model.provider.id };
|
||||||
}
|
|
||||||
|
|
||||||
@action
|
|
||||||
closeModal() {
|
|
||||||
if (this.controller.modalShowing) {
|
|
||||||
this.refresh();
|
|
||||||
this.controller.modalShowing = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true; // Continue bubbling up, so the modal actually closes
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
|
|
@ -11,8 +11,6 @@ export default class AdminPluginsChatIntegration extends DiscourseRoute {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
showSettings() {
|
showSettings() {
|
||||||
this.router.transitionTo("adminSiteSettingsCategory", "plugins", {
|
this.router.transitionTo("adminSiteSettingsCategory", "chat_integration");
|
||||||
queryParams: { filter: "chat_integration" },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
<DModalBody @id="chat_integration_error_modal">
|
|
||||||
<h4>{{i18n model.error_key}}</h4>
|
|
||||||
<pre>{{model.error_info}}</pre>
|
|
||||||
</DModalBody>
|
|
|
@ -1,60 +0,0 @@
|
||||||
<DModalBody
|
|
||||||
@title="chat_integration.edit_channel_modal.title"
|
|
||||||
@id="chat-integration-edit-channel-modal"
|
|
||||||
{{on "keyup" this.handleKeyUp}}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<form {{action "save" on="submit"}}>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="provider">
|
|
||||||
{{i18n "chat_integration.edit_channel_modal.provider"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{i18n
|
|
||||||
(concat
|
|
||||||
"chat_integration.provider." model.channel.provider ".title"
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{{#each this.model.provider.channel_parameters as |param|}}
|
|
||||||
<ChannelParamRow
|
|
||||||
@param={{param}}
|
|
||||||
@model={{this.model}}
|
|
||||||
@validParams={{this.validParams}}
|
|
||||||
@isValidParams={{this.isValidParams}}
|
|
||||||
/>
|
|
||||||
{{/each}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</DModalBody>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<DButton
|
|
||||||
@class="btn-primary btn-large"
|
|
||||||
@id="save-channel"
|
|
||||||
@title="chat_integration.edit_channel_modal.save"
|
|
||||||
@label="chat_integration.edit_channel_modal.save"
|
|
||||||
@action={{action "save"}}
|
|
||||||
@disabled={{not this.validParams}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DButton
|
|
||||||
@class="btn-large"
|
|
||||||
@title="chat_integration.edit_channel_modal.cancel"
|
|
||||||
@label="chat_integration.edit_channel_modal.cancel"
|
|
||||||
@action={{action "cancel"}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
|
@ -1,206 +0,0 @@
|
||||||
<DModalBody
|
|
||||||
@title="chat_integration.edit_rule_modal.title"
|
|
||||||
@id="chat-integration-edit-rule_modal"
|
|
||||||
{{on "keyup" this.handleKeyUp}}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<form {{action "save" on="submit"}}>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="provider">
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.provider"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{i18n
|
|
||||||
(concat
|
|
||||||
"chat_integration.provider."
|
|
||||||
this.model.channel.provider
|
|
||||||
".title"
|
|
||||||
)
|
|
||||||
}}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="channel">
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.channel"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ChannelData
|
|
||||||
@provider={{this.model.provider}}
|
|
||||||
@channel={{this.model.channel}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="filter">
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.type"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ComboBox
|
|
||||||
@name="type"
|
|
||||||
@content={{this.model.rule.available_types}}
|
|
||||||
@value={{this.model.rule.type}}
|
|
||||||
@onChange={{action (mut this.model.rule.type)}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td>
|
|
||||||
<label>
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.instructions.type"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="filter">
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.filter"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ComboBox
|
|
||||||
@name="filter"
|
|
||||||
@content={{this.model.rule.available_filters}}
|
|
||||||
@value={{this.model.rule.filter}}
|
|
||||||
@onChange={{action (mut this.model.rule.filter)}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td>
|
|
||||||
<label>
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.instructions.filter"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{{#if (eq this.model.rule.type "normal")}}
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="category">
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.category"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<CategoryChooser
|
|
||||||
@name="category"
|
|
||||||
@options={{hash none="chat_integration.all_categories"}}
|
|
||||||
@value={{this.model.rule.category_id}}
|
|
||||||
@onChange={{action (mut this.model.rule.category_id)}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td>
|
|
||||||
<label>
|
|
||||||
{{i18n
|
|
||||||
"chat_integration.edit_rule_modal.instructions.category"
|
|
||||||
}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{else}}
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="group">
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.group"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ComboBox
|
|
||||||
@content={{this.model.groups}}
|
|
||||||
@valueProperty="id"
|
|
||||||
@value={{this.model.rule.group_id}}
|
|
||||||
@onChange={{action (mut this.model.rule.group_id)}}
|
|
||||||
@options={{hash none="chat_integration.choose_group"}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td>
|
|
||||||
<label>
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.instructions.group"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{/if}}
|
|
||||||
|
|
||||||
{{#if this.siteSettings.tagging_enabled}}
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="tags">
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.tags"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<TagChooser
|
|
||||||
@placeholderKey="chat_integration.all_tags"
|
|
||||||
@name="tags"
|
|
||||||
@tags={{this.model.rule.tags}}
|
|
||||||
@everyTag="true"
|
|
||||||
@onChange={{action (mut this.model.rule.tags)}}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class="chat-instructions">
|
|
||||||
<td></td>
|
|
||||||
<td>
|
|
||||||
<label>
|
|
||||||
{{i18n "chat_integration.edit_rule_modal.instructions.tags"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{{/if}}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</DModalBody>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<DButton
|
|
||||||
@id="save-rule"
|
|
||||||
@class="btn-primary btn-large"
|
|
||||||
@title="chat_integration.edit_rule_modal.save"
|
|
||||||
@label="chat_integration.edit_rule_modal.save"
|
|
||||||
@action={{action "save"}}
|
|
||||||
@actionParam={{this.model.rule}}
|
|
||||||
@disabled={{this.saveDisabled}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DButton
|
|
||||||
@class="btn-large"
|
|
||||||
@title="chat_integration.edit_rule_modal.cancel"
|
|
||||||
@label="chat_integration.edit_rule_modal.cancel"
|
|
||||||
@action={{route-action "closeModal"}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
|
@ -1,43 +0,0 @@
|
||||||
<DModalBody
|
|
||||||
@title="chat_integration.test_modal.title"
|
|
||||||
@id="chat_integration_test_modal"
|
|
||||||
{{on "keyup" this.handleKeyUp}}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<form {{action "send" on="submit"}}>
|
|
||||||
<table>
|
|
||||||
<tbody>
|
|
||||||
<tr class="input">
|
|
||||||
<td class="label">
|
|
||||||
<label for="channel">
|
|
||||||
{{i18n "chat_integration.test_modal.topic"}}
|
|
||||||
</label>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<ChooseTopic @selectedTopicId={{this.model.topic_id}} />
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</DModalBody>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<ConditionalLoadingSpinner @condition={{this.loading}}>
|
|
||||||
<DButton
|
|
||||||
@class="btn-primary btn-large"
|
|
||||||
@id="send-test"
|
|
||||||
@title="chat_integration.test_modal.send"
|
|
||||||
@action={{action "send"}}
|
|
||||||
@label="chat_integration.test_modal.send"
|
|
||||||
@disabled={{this.sendDisabled}}
|
|
||||||
/>
|
|
||||||
<DButton
|
|
||||||
@class="btn-large"
|
|
||||||
@title="chat_integration.test_modal.close"
|
|
||||||
@action={{route-action "closeModal"}}
|
|
||||||
@label="chat_integration.test_modal.close"
|
|
||||||
/>
|
|
||||||
</ConditionalLoadingSpinner>
|
|
||||||
</div>
|
|
|
@ -11,23 +11,22 @@
|
||||||
<ChannelDetails
|
<ChannelDetails
|
||||||
@channel={{channel}}
|
@channel={{channel}}
|
||||||
@provider={{this.model.provider}}
|
@provider={{this.model.provider}}
|
||||||
@refresh={{action "refresh"}}
|
@refresh={{this.refresh}}
|
||||||
@editChannel={{action "editChannel"}}
|
@editChannel={{this.editChannel}}
|
||||||
@test={{action "testChannel"}}
|
@test={{this.testChannel}}
|
||||||
@createRule={{action "createRule"}}
|
@createRule={{this.createRule}}
|
||||||
@editRuleWithChannel={{action "editRuleWithChannel"}}
|
@editRuleWithChannel={{this.editRuleWithChannel}}
|
||||||
@showError={{action "showError"}}
|
@showError={{this.showError}}
|
||||||
/>
|
/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
<div class="table-footer">
|
<div class="table-footer">
|
||||||
<div class="pull-right">
|
<div class="pull-right">
|
||||||
<DButton
|
<DButton
|
||||||
@id="create-channel"
|
@action={{fn this.createChannel this.model.provider}}
|
||||||
@icon="plus"
|
|
||||||
@title="chat_integration.create_channel"
|
|
||||||
@label="chat_integration.create_channel"
|
@label="chat_integration.create_channel"
|
||||||
@action={{action "createChannel" this.model.provider}}
|
@icon="plus"
|
||||||
|
@id="create-channel"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -21,6 +21,7 @@
|
||||||
@title="chat_integration.settings"
|
@title="chat_integration.settings"
|
||||||
@label="chat_integration.settings"
|
@label="chat_integration.settings"
|
||||||
@action={{route-action "showSettings"}}
|
@action={{route-action "showSettings"}}
|
||||||
|
class="chat-integration-settings-button"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { ajax } from "discourse/lib/ajax";
|
||||||
import { popupAjaxError } from "discourse/lib/ajax-error";
|
import { popupAjaxError } from "discourse/lib/ajax-error";
|
||||||
import DiscourseRoute from "discourse/routes/discourse";
|
import DiscourseRoute from "discourse/routes/discourse";
|
||||||
|
|
||||||
export default class Trascript extends DiscourseRoute {
|
export default class Transcript extends DiscourseRoute {
|
||||||
@service currentUser;
|
@service currentUser;
|
||||||
@service composer;
|
@service composer;
|
||||||
@service router;
|
@service router;
|
||||||
|
@ -15,12 +15,10 @@ export default class Trascript extends DiscourseRoute {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = params.secret;
|
|
||||||
|
|
||||||
await this.router.replaceWith("discovery.latest").followRedirects();
|
await this.router.replaceWith("discovery.latest").followRedirects();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await ajax(`/chat-transcript/${secret}`);
|
const result = await ajax(`/chat-transcript/${params.secret}`);
|
||||||
this.composer.openNewTopic({
|
this.composer.openNewTopic({
|
||||||
body: result.content,
|
body: result.content,
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
div.table-footer {
|
div.table-footer {
|
||||||
margin: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.error {
|
div.error {
|
||||||
|
@ -26,7 +26,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
div.channel-details {
|
div.channel-details {
|
||||||
margin: 20px 10px;
|
margin-top: 20px;
|
||||||
border: 1px solid var(--primary-low);
|
border: 1px solid var(--primary-low);
|
||||||
|
|
||||||
div.channel-header {
|
div.channel-header {
|
||||||
|
@ -48,11 +48,8 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.admin-controls {
|
.chat-integration-settings-button {
|
||||||
padding: 10px;
|
margin-right: 10px;
|
||||||
.nav-pills {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
|
|
||||||
enabled_site_setting :chat_integration_enabled
|
enabled_site_setting :chat_integration_enabled
|
||||||
|
|
||||||
register_asset "stylesheets/chat-integration-admin.scss"
|
register_asset "stylesheets/chat-integration.scss"
|
||||||
|
|
||||||
register_svg_icon "rocket" if respond_to?(:register_svg_icon)
|
register_svg_icon "rocket" if respond_to?(:register_svg_icon)
|
||||||
register_svg_icon "fa-arrow-circle-o-right" if respond_to?(:register_svg_icon)
|
register_svg_icon "fa-arrow-circle-o-right" if respond_to?(:register_svg_icon)
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "rails_helper"
|
|
||||||
require_relative "../dummy_provider"
|
require_relative "../dummy_provider"
|
||||||
|
|
||||||
describe "Chat Controller", type: :request do
|
RSpec.describe "Chat Controller", type: :request do
|
||||||
let(:topic) { Fabricate(:post).topic }
|
let(:topic) { Fabricate(:post).topic }
|
||||||
let(:admin) { Fabricate(:admin) }
|
let(:admin) { Fabricate(:admin) }
|
||||||
let(:category) { Fabricate(:category) }
|
let(:category) { Fabricate(:category) }
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require "rails_helper"
|
RSpec.describe "Public Controller", type: :request do
|
||||||
|
|
||||||
describe "Public Controller", type: :request do
|
|
||||||
before { SiteSetting.chat_integration_enabled = true }
|
before { SiteSetting.chat_integration_enabled = true }
|
||||||
|
|
||||||
describe "loading a transcript" do
|
describe "loading a transcript" do
|
||||||
|
@ -16,7 +14,7 @@ describe "Public Controller", type: :request do
|
||||||
expect(response.body).to eq('{"content":"Some content here"}')
|
expect(response.body).to eq('{"content":"Some content here"}')
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should 404 for non-existant transcript" do
|
it "should 404 for non-existent transcript" do
|
||||||
key = "abcdefghijk"
|
key = "abcdefghijk"
|
||||||
get "/chat-transcript/#{key}.json"
|
get "/chat-transcript/#{key}.json"
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
RSpec.describe "Create channel", type: :system do
|
||||||
|
fab!(:admin)
|
||||||
|
|
||||||
|
before do
|
||||||
|
SiteSetting.chat_integration_enabled = true
|
||||||
|
SiteSetting.chat_integration_discord_enabled = true
|
||||||
|
sign_in(admin)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "creates and displays a new channel" do
|
||||||
|
visit("/admin/plugins/chat-integration/discord")
|
||||||
|
|
||||||
|
expect(page).to have_no_css(".channel-details")
|
||||||
|
|
||||||
|
click_button(I18n.t("js.chat_integration.create_channel"))
|
||||||
|
|
||||||
|
find("input[name='param-name']").fill_in(with: "bloop")
|
||||||
|
find("input[name='param-webhook_url']").fill_in(with: "https://discord.com/api/webhooks/bloop")
|
||||||
|
click_button(I18n.t("js.chat_integration.edit_channel_modal.save"))
|
||||||
|
|
||||||
|
expect(page).to have_css(".channel-details")
|
||||||
|
expect(find(".channel-info")).to have_content("bloop")
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,11 +1,6 @@
|
||||||
import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers";
|
import { click, fillIn, triggerEvent, visit } from "@ember/test-helpers";
|
||||||
import { test } from "qunit";
|
import { test } from "qunit";
|
||||||
import {
|
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||||
acceptance,
|
|
||||||
exists,
|
|
||||||
query,
|
|
||||||
queryAll,
|
|
||||||
} from "discourse/tests/helpers/qunit-helpers";
|
|
||||||
|
|
||||||
const response = (object) => {
|
const response = (object) => {
|
||||||
return [200, { "Content-Type": "text/html; charset=utf-8" }, object];
|
return [200, { "Content-Type": "text/html; charset=utf-8" }, object];
|
||||||
|
@ -91,130 +86,114 @@ acceptance("Chat Integration", function (needs) {
|
||||||
test("Rules load successfully", async function (assert) {
|
test("Rules load successfully", async function (assert) {
|
||||||
await visit("/admin/plugins/chat-integration");
|
await visit("/admin/plugins/chat-integration");
|
||||||
|
|
||||||
assert.ok(
|
assert
|
||||||
exists("#admin-plugin-chat table"),
|
.dom("#admin-plugin-chat table")
|
||||||
"it shows the table of rules"
|
.exists("it shows the table of rules");
|
||||||
);
|
|
||||||
|
|
||||||
assert.strictEqual(
|
assert
|
||||||
queryAll("#admin-plugin-chat table tr td")[0].innerText.trim(),
|
.dom("#admin-plugin-chat table tr td")
|
||||||
"All posts and replies",
|
.hasText("All posts and replies", "rule displayed");
|
||||||
"rule displayed"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create channel works", async function (assert) {
|
test("Create channel works", async function (assert) {
|
||||||
await visit("/admin/plugins/chat-integration");
|
await visit("/admin/plugins/chat-integration");
|
||||||
await click("#create-channel");
|
await click("#create-channel");
|
||||||
|
|
||||||
assert.ok(
|
assert
|
||||||
exists("#chat-integration-edit-channel-modal"),
|
.dom("#chat-integration-edit-channel-modal")
|
||||||
"it displays the modal"
|
.exists("it displays the modal");
|
||||||
);
|
assert.dom("#save-channel").isDisabled();
|
||||||
assert.ok(query("#save-channel").disabled, "it disables the save button");
|
|
||||||
|
|
||||||
await fillIn("#chat-integration-edit-channel-modal input", "#general");
|
await fillIn("#chat-integration-edit-channel-modal input", "#general");
|
||||||
|
|
||||||
assert.notOk(query("#save-channel").disabled, "it enables the save button");
|
assert.dom("#save-channel").isEnabled();
|
||||||
|
|
||||||
await click("#save-channel");
|
await click("#save-channel");
|
||||||
|
|
||||||
assert.notOk(
|
assert
|
||||||
exists("#chat-integration-edit-channel-modal"),
|
.dom("#chat-integration-edit-channel-modal")
|
||||||
"modal closes on save"
|
.doesNotExist("modal closes on save");
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Edit channel works", async function (assert) {
|
test("Edit channel works", async function (assert) {
|
||||||
await visit("/admin/plugins/chat-integration");
|
await visit("/admin/plugins/chat-integration");
|
||||||
await click(".channel-header button");
|
await click(".channel-header button");
|
||||||
|
|
||||||
assert.ok(
|
assert
|
||||||
exists("#chat-integration-edit-channel-modal"),
|
.dom("#chat-integration-edit-channel-modal")
|
||||||
"it displays the modal"
|
.exists("it displays the modal");
|
||||||
);
|
assert.dom("#save-channel").isEnabled();
|
||||||
assert.notOk(query("#save-channel").disabled, "save is enabled");
|
|
||||||
|
|
||||||
await fillIn("#chat-integration-edit-channel-modal input", " general");
|
await fillIn("#chat-integration-edit-channel-modal input", " general");
|
||||||
|
assert.dom("#save-channel").isDisabled();
|
||||||
assert.ok(query("#save-channel").disabled, "it disables the save button");
|
|
||||||
|
|
||||||
await fillIn("#chat-integration-edit-channel-modal input", "#random");
|
await fillIn("#chat-integration-edit-channel-modal input", "#random");
|
||||||
|
assert.dom("#save-channel").isEnabled();
|
||||||
|
|
||||||
// Press enter
|
// Press enter
|
||||||
await triggerKeyEvent(
|
await triggerEvent("#chat-integration-edit-channel-modal", "submit");
|
||||||
"#chat-integration-edit-channel-modal",
|
|
||||||
"keydown",
|
|
||||||
"Enter"
|
|
||||||
);
|
|
||||||
|
|
||||||
assert.notOk(
|
assert
|
||||||
exists("#chat-integration-edit-channel-modal"),
|
.dom("#chat-integration-edit-channel-modal")
|
||||||
"modal saves on enter"
|
.doesNotExist("modal saves on enter");
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Create rule works", async function (assert) {
|
test("Create rule works", async function (assert) {
|
||||||
await visit("/admin/plugins/chat-integration");
|
await visit("/admin/plugins/chat-integration");
|
||||||
|
|
||||||
assert.ok(exists(".channel-footer button"), "create button is displayed");
|
assert.dom(".channel-footer button").exists("create button is displayed");
|
||||||
|
|
||||||
await click(".channel-footer button");
|
await click(".channel-footer button");
|
||||||
|
|
||||||
assert.ok(
|
assert
|
||||||
exists("#chat-integration-edit-rule_modal"),
|
.dom("#chat-integration-edit-rule_modal")
|
||||||
"modal opens on edit"
|
.exists("modal opens on edit");
|
||||||
);
|
assert.dom("#save-rule").isEnabled();
|
||||||
assert.notOk(query("#save-rule").disabled, "save is enabled");
|
|
||||||
|
|
||||||
await click("#save-rule");
|
await click("#save-rule");
|
||||||
|
|
||||||
assert.notOk(
|
assert
|
||||||
exists("#chat-integration-edit-rule_modal"),
|
.dom("#chat-integration-edit-rule_modal")
|
||||||
"modal closes on save"
|
.doesNotExist("modal closes on save");
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Edit rule works", async function (assert) {
|
test("Edit rule works", async function (assert) {
|
||||||
await visit("/admin/plugins/chat-integration");
|
await visit("/admin/plugins/chat-integration");
|
||||||
|
|
||||||
assert.ok(exists(".edit"), "edit button is displayed");
|
assert.dom(".edit").exists("edit button is displayed");
|
||||||
|
|
||||||
await click(".edit");
|
await click(".edit");
|
||||||
|
|
||||||
assert.ok(
|
assert
|
||||||
exists("#chat-integration-edit-rule_modal"),
|
.dom("#chat-integration-edit-rule_modal")
|
||||||
"modal opens on edit"
|
.exists("modal opens on edit");
|
||||||
);
|
assert.dom("#save-rule").isEnabled();
|
||||||
assert.notOk(query("#save-rule").disabled, "it enables the save button");
|
|
||||||
|
|
||||||
await click("#save-rule");
|
await click("#save-rule");
|
||||||
|
|
||||||
assert.notOk(
|
assert
|
||||||
exists("#chat-integration-edit-rule_modal"),
|
.dom("#chat-integration-edit-rule_modal")
|
||||||
"modal closes on save"
|
.doesNotExist("modal closes on save");
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Delete channel works", async function (assert) {
|
test("Delete channel works", async function (assert) {
|
||||||
await visit("/admin/plugins/chat-integration");
|
await visit("/admin/plugins/chat-integration");
|
||||||
|
|
||||||
assert.ok(
|
assert
|
||||||
exists(".channel-header .delete-channel"),
|
.dom(".channel-header .delete-channel")
|
||||||
"delete buttons exists"
|
.exists("delete buttons exists");
|
||||||
);
|
|
||||||
await click(".channel-header .delete-channel");
|
await click(".channel-header .delete-channel");
|
||||||
|
|
||||||
assert.ok(exists("div.dialog-content"), "modal is displayed");
|
assert.dom("div.dialog-content").exists("dialog is displayed");
|
||||||
await click("div.dialog-content .btn-danger");
|
await click("div.dialog-content .btn-danger");
|
||||||
|
|
||||||
assert.notOk(exists("div.dialog-content"), "modal has closed");
|
assert.dom("div.dialog-content").doesNotExist("dialog has closed");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Delete rule works", async function (assert) {
|
test("Delete rule works", async function (assert) {
|
||||||
await visit("/admin/plugins/chat-integration");
|
await visit("/admin/plugins/chat-integration");
|
||||||
|
|
||||||
assert.ok(exists(".delete"));
|
assert.dom(".delete").exists();
|
||||||
await click(".delete");
|
await click(".delete");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -223,23 +202,21 @@ acceptance("Chat Integration", function (needs) {
|
||||||
|
|
||||||
await click(".btn-chat-test");
|
await click(".btn-chat-test");
|
||||||
|
|
||||||
assert.ok(exists("#chat_integration_test_modal"), "it displays the modal");
|
assert.dom("#chat_integration_test_modal").exists("it displays the modal");
|
||||||
assert.ok(query("#send-test").disabled, "it disables the send button");
|
assert.dom("#send-test").isDisabled();
|
||||||
|
|
||||||
await fillIn("#choose-topic-title", "9318");
|
await fillIn("#choose-topic-title", "9318");
|
||||||
await click("#chat_integration_test_modal .radio");
|
await click("#chat_integration_test_modal .radio");
|
||||||
|
|
||||||
assert.notOk(query("#send-test").disabled, "it enables the send button");
|
assert.dom("#send-test").isEnabled();
|
||||||
|
|
||||||
await click("#send-test");
|
await click("#send-test");
|
||||||
|
|
||||||
assert.ok(
|
assert
|
||||||
exists("#chat_integration_test_modal"),
|
.dom("#chat_integration_test_modal")
|
||||||
"modal doesn't close on send"
|
.exists("modal doesn't close on send");
|
||||||
);
|
assert
|
||||||
assert.ok(
|
.dom("#modal-alert.alert-success")
|
||||||
exists("#modal-alert.alert-success"),
|
.exists("success message displayed");
|
||||||
"success message displayed"
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue