DEV: Ember upgrade (#155)

This commit is contained in:
Keegan George 2023-01-23 10:30:48 -08:00 committed by GitHub
parent 91d2cfb952
commit bdc2f27a2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 772 additions and 757 deletions

View File

@ -0,0 +1,19 @@
{{#each @provider.channel_parameters as |param|}}
{{#unless param.hidden}}
<div class="channel-info">
<span class="field-name">
{{i18n
(concat
"chat_integration.provider."
@channel.provider
".param."
param.key
".title"
)
}}:
</span>
<span class="field-value">{{get @channel.data param.key}}</span>
<br />
</div>
{{/unless}}
{{/each}}

View File

@ -1,5 +0,0 @@
import Component from "@ember/component";
export default Component.extend({
classNames: ["channel-info"],
});

View File

@ -0,0 +1,78 @@
<div class="channel-details">
<div class="channel-header">
<div class="pull-right">
<DButton
@icon="pencil-alt"
@title="chat_integration.edit_channel"
@label="chat_integration.edit_channel"
@action={{action @editChannel @channel}}
/>
<DButton
@icon="rocket"
@title="chat_integration.test_channel"
@label="chat_integration.test_channel"
@action={{action @test @channel}}
@class="btn-chat-test"
/>
<DButton
@icon="trash-alt"
@title="chat_integration.delete_channel"
@label="chat_integration.delete_channel"
@action={{action this.deleteChannel @channel}}
@class="cancel delete-channel"
/>
</div>
<span class="channel-title">
{{#if @channel.error_key}}
<DButton
@class="delete btn-danger"
@icon="exclamation-triangle"
@action={{action @showError @channel}}
/>
{{/if}}
<ChannelData @provider={{@provider}} @channel={{@channel}} />
</span>
</div>
<div class="channel-body">
<table>
<thead>
<tr>
<th>{{i18n "chat_integration.rule_table.filter"}}</th>
<th>{{i18n "chat_integration.rule_table.category"}}</th>
{{#if this.siteSettings.tagging_enabled}}
<th>{{i18n "chat_integration.rule_table.tags"}}</th>
{{/if}}
<th></th>
</tr>
</thead>
<tbody>
{{#each @channel.rules as |rule|}}
<RuleRow
@rule={{rule}}
@edit={{action @editRuleWithChannel rule @channel}}
@refresh={{@refresh}}
/>
{{/each}}
</tbody>
</table>
</div>
<div class="channel-footer">
<div class="pull-right">
<DButton
@class=""
@icon="plus"
@title="chat_integration.create_rule"
@label="chat_integration.create_rule"
@action={{action @createRule @channel}}
/>
</div>
</div>
</div>

View File

@ -1,27 +1,23 @@
import Component from "@ember/component";
import Component from "@glimmer/component";
import { popupAjaxError } from "discourse/lib/ajax-error";
import I18n from "I18n";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
export default Component.extend({
dialog: service(),
classNames: ["channel-details"],
export default class ChannelDetails extends Component {
@service dialog;
@service siteSettings;
actions: {
deleteChannel(channel) {
this.dialog.deleteConfirm({
message: I18n.t("chat_integration.channel_delete_confirm"),
didConfirm: () => {
return channel
.destroyRecord()
.then(() => this.refresh())
.catch(popupAjaxError);
},
});
},
editRule(rule) {
this.editRuleWithChannel(rule, this.get("channel"));
},
},
});
@action
deleteChannel(channel) {
this.dialog.deleteConfirm({
message: I18n.t("chat_integration.channel_delete_confirm"),
didConfirm: () => {
return channel
.destroyRecord()
.then(() => this.args.refresh())
.catch(popupAjaxError);
},
});
}
}

View File

@ -0,0 +1,42 @@
<tr class="input">
<td class="label">
<label for="param-{{@param.key}}">
{{i18n
(concat
"chat_integration.provider."
@model.channel.provider
".param."
@param.key
".title"
)
}}
</label>
</td>
<td>
<Input
name={{concat "param-" @param.key}}
@value={{this.inputValue}}
{{on "change" this.updateValue}}
/>
<InputTip @validation={{this.validate}} />
</td>
</tr>
<tr class="chat-instructions">
<td></td>
<td>
<label>
{{i18n
(concat
"chat_integration.provider."
@model.channel.provider
".param."
@param.key
".help"
)
}}
</label>
</td>
</tr>

View File

@ -0,0 +1,51 @@
import Component from "@glimmer/component";
import EmberObject, { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";
import I18n from "I18n";
export default class ChannelParamRow extends Component {
@tracked inputValue = this.args.model.channel.data[this.args.param.key] || "";
get validate() {
const parameter = this.args.param;
const regString = parameter.regex;
const regex = new RegExp(regString);
if (this.inputValue === "") {
// 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,
reason: I18n.t(
"chat_integration.edit_channel_modal.channel_validation.ok"
),
});
} else {
// Failed regex
this.args.isValidParams(false);
return EmberObject.create({
failed: true,
reason: I18n.t(
"chat_integration.edit_channel_modal.channel_validation.fail"
),
});
}
}
@action
updateValue(event) {
this.args.model.channel.data[this.args.param.key] = event.target.value;
}
}

View File

@ -0,0 +1,47 @@
<tr>
<td>
{{@rule.filterName}}
</td>
<td>
{{#if this.isCategory}}
{{#if @rule.category}}
{{category-link @rule.category allowUncategorized="true" link="false"}}
{{else}}
{{i18n "chat_integration.all_categories"}}
{{/if}}
{{else if this.isMention}}
{{i18n "chat_integration.group_mention_template" name=@rule.group_name}}
{{else if this.isMessage}}
{{i18n "chat_integration.group_message_template" name=@rule.group_name}}
{{/if}}
</td>
<td>
{{#if this.siteSettings.tagging_enabled}}
{{#if @rule.tags}}
{{@rule.tags}}
{{else}}
{{i18n "chat_integration.all_tags"}}
{{/if}}
{{/if}}
</td>
<td>
<DButton
@class="edit"
@icon="pencil-alt"
@title="chat_integration.rule_table.edit_rule"
@action={{@edit}}
@actionParam={{@rule}}
/>
<DButton
@class="delete"
@icon="far-trash-alt"
@title="chat_integration.rule_table.delete_rule"
@action={{action this.delete}}
@actionParam={{@rule}}
/>
</td>
</tr>

View File

@ -1,31 +1,27 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import Component from "@glimmer/component";
import { popupAjaxError } from "discourse/lib/ajax-error";
import computed from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
export default class RuleRow extends Component {
@service siteSettings;
export default Component.extend({
tagName: "tr",
get isCategory() {
return this.args.rule.type === "normal";
}
@computed("rule.type")
isCategory(type) {
return type === "normal";
},
get isMessage() {
return this.args.rule.type === "group_message";
}
@computed("rule.type")
isMessage(type) {
return type === "group_message";
},
get isMention() {
return this.args.rule.type === "group_mention";
}
@computed("rule.type")
isMention(type) {
return type === "group_mention";
},
actions: {
delete(rule) {
rule
.destroyRecord()
.then(() => this.refresh())
.catch(popupAjaxError);
},
},
});
@action
delete(rule) {
rule
.destroyRecord()
.then(() => this.args.refresh())
.catch(popupAjaxError);
}
}

View File

@ -1,12 +1,20 @@
import Controller from "@ember/controller";
import showModal from "discourse/lib/show-modal";
import computed from "discourse-common/utils/decorators";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
export default Controller.extend({
modalShowing: false,
const MODALS = {
editChannel: "admin-plugins-chat-integration-edit-channel",
testChannel: "admin-plugins-chat-integration-test",
editRule: "admin-plugins-chat-integration-edit-rule",
channelError: "admin-plugins-chat-integration-channel-error",
};
@computed("model.channels")
anyErrors(channels) {
export default class AdminPluginsChatIntegrationEditRule extends Controller {
@tracked modalShowing = false;
get anyErrors() {
const channels = this.model.channels;
let anyErrors = false;
channels.forEach((channel) => {
@ -16,90 +24,83 @@ export default Controller.extend({
});
return anyErrors;
},
}
actions: {
createChannel() {
this.set("modalShowing", true);
triggerModal(model, modal) {
this.modalShowing = true;
const model = {
showModal(modal, {
model,
admin: true,
});
}
@action
createChannel() {
return this.triggerModal(
{
channel: this.store.createRecord("channel", {
provider: this.get("model.provider.id"),
provider: this.model.provider.id,
data: {},
}),
provider: this.get("model.provider"),
};
provider: this.model.provider,
},
MODALS.editChannel
);
}
showModal("admin-plugins-chat-integration-edit-channel", {
model,
admin: true,
});
},
editChannel(channel) {
this.set("modalShowing", true);
const model = {
@action
editChannel(channel) {
return this.triggerModal(
{
channel,
provider: this.get("model.provider"),
};
provider: this.model.provider,
},
MODALS.editChannel
);
}
showModal("admin-plugins-chat-integration-edit-channel", {
model,
admin: true,
});
},
@action
testChannel(channel) {
return this.triggerModal({ channel }, MODALS.testChannel);
}
testChannel(channel) {
this.set("modalShowing", true);
showModal("admin-plugins-chat-integration-test", {
model: { channel },
admin: true,
});
},
createRule(channel) {
this.set("modalShowing", true);
const model = {
@action
createRule(channel) {
return this.triggerModal(
{
rule: this.store.createRecord("rule", {
channel_id: channel.id,
channel,
}),
channel,
provider: this.get("model.provider"),
groups: this.get("model.groups"),
};
provider: this.model.provider,
groups: this.model.groups,
},
MODALS.editRule
);
}
showModal("admin-plugins-chat-integration-edit-rule", {
model,
admin: true,
});
},
editRuleWithChannel(rule, channel) {
this.set("modalShowing", true);
const model = {
@action
editRuleWithChannel(rule, channel) {
return this.triggerModal(
{
rule,
channel,
provider: this.get("model.provider"),
groups: this.get("model.groups"),
};
provider: this.model.provider,
groups: this.model.groups,
},
MODALS.editRule
);
}
showModal("admin-plugins-chat-integration-edit-rule", {
model,
admin: true,
});
},
@action
showError(channel) {
return this.triggerModal({ channel }, MODALS.channelError);
}
showError(channel) {
this.set("modalShowing", true);
showModal("admin-plugins-chat-integration-channel-error", {
model: channel,
admin: true,
});
},
},
});
@action
refresh() {
this.send("refreshProvider");
}
}

View File

@ -1,3 +1,3 @@
import Controller from "@ember/controller";
export default Controller.extend({});
export default class AdminPluginsChatIntegration extends Controller {}

View File

@ -1,131 +1,42 @@
import Controller from "@ember/controller";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { popupAjaxError } from "discourse/lib/ajax-error";
import EmberObject, {
defineProperty,
computed as emberComputed,
} from "@ember/object";
import computed, { observes, on } from "discourse-common/utils/decorators";
import { schedule } from "@ember/runloop";
import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";
export default Controller.extend(ModalFunctionality, {
@on("init")
setupKeydown() {
schedule("afterRender", () => {
$("#chat-integration-edit-channel-modal").keydown((e) => {
if (e.keyCode === 13) {
this.send("save");
}
});
});
},
export default class AdminPluginsChatIntegrationEditChannel extends Controller.extend(
ModalFunctionality
) {
@tracked validParams = false;
// The validation property must be defined at runtime since the possible parameters vary by provider
@observes("model")
setupValidations() {
if (this.get("model.provider")) {
const theKeys = this.get("model.provider.channel_parameters").map(
(param) => param["key"]
);
defineProperty(
this,
"paramValidation",
emberComputed(
`model.channel.data.{${theKeys.join(",")}}`,
this._paramValidation
)
);
this.notifyPropertyChange("paramValidation");
@action
isValidParams(validity) {
return (this.validParams = validity);
}
@action
handleKeyUp(e) {
if (e.code === "Enter" && this.validParams) {
this.save();
}
},
}
validate(parameter) {
const regString = parameter.regex;
const regex = new RegExp(regString);
let val = this.get(`model.channel.data.${parameter.key}`);
@action
cancel() {
this.send("closeModal");
}
if (val === undefined) {
val = "";
@action
save() {
if (!this.validParams) {
return;
}
if (val === "") {
// Fail silently if field blank
return EmberObject.create({
failed: true,
});
} else if (!regString) {
// Pass silently if no regex available for provider
return EmberObject.create({
ok: true,
});
} else if (regex.test(val)) {
// Test against regex
return EmberObject.create({
ok: true,
reason: I18n.t(
"chat_integration.edit_channel_modal.channel_validation.ok"
),
});
} else {
// Failed regex
return EmberObject.create({
failed: true,
reason: I18n.t(
"chat_integration.edit_channel_modal.channel_validation.fail"
),
});
}
},
_paramValidation() {
const response = {};
const parameters = this.get("model.provider.channel_parameters");
parameters.forEach((parameter) => {
response[parameter.key] = this.validate(parameter);
});
return response;
},
@computed("paramValidation")
saveDisabled(paramValidation) {
if (!paramValidation) {
return true;
}
let invalid = false;
Object.keys(paramValidation).forEach((key) => {
if (!paramValidation[key]) {
invalid = true;
}
if (!paramValidation[key]["ok"]) {
invalid = true;
}
});
return invalid;
},
actions: {
cancel() {
this.send("closeModal");
},
save() {
if (this.get("saveDisabled")) {
return;
}
this.get("model.channel")
.save()
.then(() => {
this.send("closeModal");
})
.catch(popupAjaxError);
},
},
});
this.model.channel
.save()
.then(() => {
this.send("closeModal");
})
.catch(popupAjaxError);
}
}

View File

@ -1,38 +1,51 @@
import Controller from "@ember/controller";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { popupAjaxError } from "discourse/lib/ajax-error";
import computed, { on } from "discourse-common/utils/decorators";
import { schedule } from "@ember/runloop";
import { tracked } from "@glimmer/tracking";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
export default Controller.extend(ModalFunctionality, {
saveDisabled: false,
export default class AdminPluginsChatIntegrationEditRule extends Controller.extend(
ModalFunctionality
) {
@service siteSettings;
@tracked saveDisabled = false;
@on("init")
setupKeydown() {
schedule("afterRender", () => {
$("#chat-integration-edit-channel-modal").keydown((e) => {
if (e.keyCode === 13) {
this.send("save");
}
});
});
},
get showCategory() {
return this.model.rule.type === "normal";
}
@computed("model.rule.type")
showCategory(type) {
return type === "normal";
},
get currentRuleType() {
return this.model.rule.type;
}
actions: {
save(rule) {
if (this.get("saveDisabled")) {
return;
}
@action
save(rule) {
if (this.saveDisabled) {
return;
}
rule
.save()
.then(() => this.send("closeModal"))
.catch(popupAjaxError);
},
},
});
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;
}
}
}

View File

@ -1,47 +1,43 @@
import Controller from "@ember/controller";
import { not } from "@ember/object/computed";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import computed, { on } from "discourse-common/utils/decorators";
import { schedule } from "@ember/runloop";
import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";
export default Controller.extend(ModalFunctionality, {
@on("init")
setupKeydown() {
schedule("afterRender", () => {
$("#chat_integration_test_modal").keydown((e) => {
if (e.keyCode === 13) {
this.send("send");
}
});
});
},
export default class AdminPluginsChatIntegrationTest extends Controller.extend(
ModalFunctionality
) {
@tracked loading = false;
@not("model.topic_id") sendDisabled;
@computed("model.topic_id")
sendDisabled(topicId) {
return !topicId;
},
@action
handleKeyUp(e) {
if (e.code === "Enter" && !this.sendDisabled) {
this.send();
}
}
actions: {
send() {
if (this.get("sendDisabled")) {
return;
}
this.set("loading", true);
@action
send() {
if (this.sendDisabled) {
return;
}
this.loading = true;
ajax("/admin/plugins/chat-integration/test", {
data: {
channel_id: this.get("model.channel.id"),
topic_id: this.get("model.topic_id"),
},
type: "POST",
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");
})
.then(() => {
this.set("loading", false);
this.flash(I18n.t("chat_integration.test_modal.success"), "success");
})
.catch(popupAjaxError);
},
},
});
.catch(popupAjaxError);
}
}

View File

@ -1,11 +1,11 @@
import RestModel from "discourse/models/rest";
export default RestModel.extend({
export default class Channel extends RestModel {
updateProperties() {
return this.getProperties(["data"]);
},
}
createProperties() {
return this.getProperties(["provider", "data"]);
},
});
}
}

View File

@ -1,3 +1,3 @@
import RestModel from "discourse/models/rest";
export default RestModel.extend({});
export default class Provider extends RestModel {}

View File

@ -1,12 +1,31 @@
import I18n from "I18n";
import RestModel from "discourse/models/rest";
import Category from "discourse/models/category";
import computed, { observes } from "discourse-common/utils/decorators";
import { tracked } from "@glimmer/tracking";
export default RestModel.extend({
@computed("channel.provider")
available_filters(provider) {
export default class Rule extends RestModel {
@tracked type = "normal";
@tracked category_id = null;
@tracked tags = null;
@tracked channel_id = null;
@tracked filter = "watch";
@tracked error_key = null;
available_types = [
{ id: "normal", name: I18n.t("chat_integration.type.normal") },
{
id: "group_message",
name: I18n.t("chat_integration.type.group_message"),
},
{
id: "group_mention",
name: I18n.t("chat_integration.type.group_mention"),
},
];
get available_filters() {
const available = [];
const provider = this.channel.provider;
if (provider === "slack") {
available.push({
@ -35,51 +54,21 @@ export default RestModel.extend({
);
return available;
},
}
available_types: [
{ id: "normal", name: I18n.t("chat_integration.type.normal") },
{
id: "group_message",
name: I18n.t("chat_integration.type.group_message"),
},
{
id: "group_mention",
name: I18n.t("chat_integration.type.group_mention"),
},
],
get category() {
const categoryId = this.category_id;
category_id: null,
tags: null,
channel_id: null,
filter: "watch",
type: "normal",
error_key: null,
@observes("type")
removeUnneededInfo() {
const type = this.get("type");
if (type === "normal") {
this.set("group_id", null);
} else {
this.set("category_id", null);
}
},
@computed("category_id")
category(categoryId) {
if (categoryId) {
return Category.findById(categoryId);
} else {
return false;
}
},
}
@computed("filter")
filterName(filter) {
return I18n.t(`chat_integration.filter.${filter}`);
},
get filterName() {
return I18n.t(`chat_integration.filter.${this.filter}`);
}
updateProperties() {
return this.getProperties([
@ -89,7 +78,7 @@ export default RestModel.extend({
"tags",
"filter",
]);
},
}
createProperties() {
return this.getProperties([
@ -100,5 +89,5 @@ export default RestModel.extend({
"tags",
"filter",
]);
},
});
}
}

View File

@ -1,6 +1,6 @@
import DiscourseRoute from "discourse/routes/discourse";
export default DiscourseRoute.extend({
export default class AdminPluginsChatIntegrationIndex extends DiscourseRoute {
afterModel(model) {
if (model.totalRows > 0) {
this.transitionTo(
@ -8,5 +8,5 @@ export default DiscourseRoute.extend({
model.get("firstObject").name
);
}
},
});
}
}

View File

@ -3,7 +3,7 @@ import Group from "discourse/models/group";
import { action } from "@ember/object";
import RSVP from "rsvp";
export default DiscourseRoute.extend({
export default class AdminPluginsChatIntegrationProvider extends DiscourseRoute {
model(params) {
return RSVP.hash({
channels: this.store.findAll("channel", { provider: params.provider }),
@ -26,24 +26,24 @@ export default DiscourseRoute.extend({
return value;
});
},
}
serialize(model) {
return { provider: model["provider"].get("id") };
},
}
@action
closeModal() {
if (this.get("controller.modalShowing")) {
if (this.controller.modalShowing) {
this.refresh();
this.set("controller.modalShowing", false);
this.controller.modalShowing = false;
}
return true; // Continue bubbling up, so the modal actually closes
},
}
@action
refreshProvider() {
this.refresh();
},
});
}
}

View File

@ -1,15 +1,15 @@
import DiscourseRoute from "discourse/routes/discourse";
import { action } from "@ember/object";
export default DiscourseRoute.extend({
export default class AdminPluginsChatIntegration extends DiscourseRoute {
model() {
return this.store.findAll("provider");
},
}
@action
showSettings() {
this.transitionTo("adminSiteSettingsCategory", "plugins", {
queryParams: { filter: "chat_integration" },
});
},
});
}
}

View File

@ -1,4 +1,4 @@
{{#d-modal-body id="chat_integration_error_modal"}}
<DModalBody @id="chat_integration_error_modal">
<h4>{{i18n model.error_key}}</h4>
<pre>{{model.error_info}}</pre>
{{/d-modal-body}}
</DModalBody>

View File

@ -1,15 +1,18 @@
{{#d-modal-body
id="chat-integration-edit-channel-modal"
title="chat_integration.edit_channel_modal.title"
}}
<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 class="label">
<label for="provider">
{{i18n "chat_integration.edit_channel_modal.provider"}}
</label>
</td>
<td>
{{i18n
(concat
@ -24,63 +27,34 @@
<td></td>
</tr>
{{#each model.provider.channel_parameters as |param|}}
<tr class="input">
<td class="label"><label for="param-{{param.key}}">{{i18n
(concat
"chat_integration.provider."
model.channel.provider
".param."
param.key
".title"
)
}}</label></td>
<td>
{{text-field
name=(concat "param-" param.key)
value=(mut (get model.channel.data param.key))
}}
&nbsp;
{{#if (get model.channel.data param.key)}}
{{input-tip validation=(get paramValidation param.key)}}
{{/if}}
</td>
</tr>
<tr class="chat-instructions">
<td></td>
<td><label>{{i18n
(concat
"chat_integration.provider."
model.channel.provider
".param."
param.key
".help"
)
}}</label></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>
{{/d-modal-body}}
</DModalBody>
<div class="modal-footer">
{{d-button
id="save-channel"
class="btn-primary btn-large"
action=(action "save")
title="chat_integration.edit_channel_modal.save"
label="chat_integration.edit_channel_modal.save"
disabled=saveDisabled
}}
<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)}}
/>
{{d-button
class="btn-large"
action=(action "cancel")
title="chat_integration.edit_channel_modal.cancel"
label="chat_integration.edit_channel_modal.cancel"
}}
<DButton
@class="btn-large"
@title="chat_integration.edit_channel_modal.cancel"
@label="chat_integration.edit_channel_modal.cancel"
@action={{action "cancel"}}
/>
</div>

View File

@ -1,19 +1,24 @@
{{#d-modal-body
id="chat-integration-edit-rule_modal"
title="chat_integration.edit_rule_modal.title"
}}
<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 class="label">
<label for="provider">
{{i18n "chat_integration.edit_rule_modal.provider"}}
</label>
</td>
<td>
{{i18n
(concat
"chat_integration.provider." model.channel.provider ".title"
"chat_integration.provider."
this.model.channel.provider
".title"
)
}}
</td>
@ -25,11 +30,16 @@
</tr>
<tr class="input">
<td class="label"><label for="channel">{{i18n
"chat_integration.edit_rule_modal.channel"
}}</label></td>
<td class="label">
<label for="channel">
{{i18n "chat_integration.edit_rule_modal.channel"}}
</label>
</td>
<td>
{{channel-data provider=model.provider channel=model.channel}}
<ChannelData
@provider={{this.model.provider}}
@channel={{this.model.channel}}
/>
</td>
</tr>
@ -39,131 +49,158 @@
</tr>
<tr class="input">
<td class="label"><label for="filter">{{i18n
"chat_integration.edit_rule_modal.type"
}}</label></td>
<td class="label">
<label for="filter">
{{i18n "chat_integration.edit_rule_modal.type"}}
</label>
</td>
<td>
{{combo-box
name="type"
content=model.rule.available_types
value=model.rule.type
}}
<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>
<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 class="label">
<label for="filter">
{{i18n "chat_integration.edit_rule_modal.filter"}}
</label>
</td>
<td>
{{combo-box
name="filter"
content=model.rule.available_filters
value=model.rule.filter
}}
<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>
<td>
<label>
{{i18n "chat_integration.edit_rule_modal.instructions.filter"}}
</label>
</td>
</tr>
{{#if showCategory}}
{{#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 class="label">
<label for="category">
{{i18n "chat_integration.edit_rule_modal.category"}}
</label>
</td>
<td>
{{category-chooser
name="category"
none="chat_integration.all_categories"
value=model.rule.category_id
}}
<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
<td>
<label>
{{i18n
"chat_integration.edit_rule_modal.instructions.category"
}}</label></td>
}}
</label>
</td>
</tr>
{{else}}
<tr class="input">
<td class="label"><label for="group">{{i18n
"chat_integration.edit_rule_modal.group"
}}</label></td>
<td class="label">
<label for="group">
{{i18n "chat_integration.edit_rule_modal.group"}}
</label>
</td>
<td>
{{combo-box
content=model.groups
valueAttribute="id"
value=model.rule.group_id
none="chat_integration.choose_group"
}}
<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>
<td>
<label>
{{i18n "chat_integration.edit_rule_modal.instructions.group"}}
</label>
</td>
</tr>
{{/if}}
{{#if siteSettings.tagging_enabled}}
{{#if this.siteSettings.tagging_enabled}}
<tr class="input">
<td class="label"><label for="tags">{{i18n
"chat_integration.edit_rule_modal.tags"
}}</label></td>
<td class="label">
<label for="tags">
{{i18n "chat_integration.edit_rule_modal.tags"}}
</label>
</td>
<td>
{{tag-chooser
placeholderKey="chat_integration.all_tags"
name="tags"
tags=model.rule.tags
everyTag=true
}}
<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>
<td>
<label>
{{i18n "chat_integration.edit_rule_modal.instructions.tags"}}
</label>
</td>
</tr>
{{/if}}
</tbody>
</table>
</form>
</div>
{{/d-modal-body}}
</DModalBody>
<div class="modal-footer">
{{d-button
id="save-rule"
class="btn-primary btn-large"
action=(action "save")
actionParam=model.rule
title="chat_integration.edit_rule_modal.save"
label="chat_integration.edit_rule_modal.save"
disabled=saveDisabled
}}
<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}}
/>
{{d-button
class="btn-large"
action=(route-action "closeModal")
title="chat_integration.edit_rule_modal.cancel"
label="chat_integration.edit_rule_modal.cancel"
}}
<DButton
@class="btn-large"
@title="chat_integration.edit_rule_modal.cancel"
@label="chat_integration.edit_rule_modal.cancel"
@action={{route-action "closeModal"}}
/>
</div>

View File

@ -1,41 +1,43 @@
{{#d-modal-body
id="chat_integration_test_modal"
title="chat_integration.test_modal.title"
}}
<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 class="label">
<label for="channel">
{{i18n "chat_integration.test_modal.topic"}}
</label>
</td>
<td>
{{choose-topic selectedTopicId=model.topic_id}}
<ChooseTopic @selectedTopicId={{this.model.topic_id}} />
</td>
</tr>
</tbody>
</table>
</form>
</div>
{{/d-modal-body}}
</DModalBody>
<div class="modal-footer">
{{#conditional-loading-spinner condition=loading}}
{{d-button
id="send-test"
class="btn-primary btn-large"
action=(action "send")
title="chat_integration.test_modal.send"
label="chat_integration.test_modal.send"
disabled=sendDisabled
}}
{{d-button
class="btn-large"
action=(route-action "closeModal")
title="chat_integration.test_modal.close"
label="chat_integration.test_modal.close"
}}
{{/conditional-loading-spinner}}
<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>

View File

@ -0,0 +1,33 @@
{{#if this.anyErrors}}
<div class="error">
{{d-icon "exclamation-triangle"}}
<span class="error-message">
{{i18n "chat_integration.channels_with_errors"}}
</span>
</div>
{{/if}}
{{#each this.model.channels.content as |channel|}}
<ChannelDetails
@channel={{channel}}
@provider={{this.model.provider}}
@refresh={{action "refresh"}}
@editChannel={{action "editChannel"}}
@test={{action "testChannel"}}
@createRule={{action "createRule"}}
@editRuleWithChannel={{action "editRuleWithChannel"}}
@showError={{action "showError"}}
/>
{{/each}}
<div class="table-footer">
<div class="pull-right">
<DButton
@id="create-channel"
@icon="plus"
@title="chat_integration.create_channel"
@label="chat_integration.create_channel"
@action={{action "createChannel" this.model.provider}}
/>
</div>
</div>

View File

@ -0,0 +1,30 @@
<div id="admin-plugin-chat">
<div class="admin-controls">
<div class="admin-controls-chat-providers">
<ul class="nav nav-pills">
{{#each this.model as |provider|}}
<NavItem
@route="adminPlugins.chat-integration.provider"
@routeParam={{provider.name}}
@label={{(concat
"chat_integration.provider." provider.name ".title"
)}}
/>
{{/each}}
</ul>
</div>
<DButton
@icon="cog"
@title="chat_integration.settings"
@label="chat_integration.settings"
@action={{route-action "showSettings"}}
/>
</div>
{{#unless this.model.totalRows}}
{{i18n "chat_integration.no_providers"}}
{{/unless}}
{{outlet}}
</div>

View File

@ -3,7 +3,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
import DiscourseRoute from "discourse/routes/discourse";
import { next } from "@ember/runloop";
export default DiscourseRoute.extend({
export default class Trascript extends DiscourseRoute {
model(params) {
if (this.currentUser) {
const secret = params.secret;
@ -28,5 +28,5 @@ export default DiscourseRoute.extend({
this.session.set("shouldRedirectToUrl", window.location.href);
this.replaceWith("login");
}
},
});
}
}

View File

@ -1,34 +0,0 @@
{{#if anyErrors}}
<div class="error">
{{d-icon "exclamation-triangle"}}
<span class="error-message">{{i18n
"chat_integration.channels_with_errors"
}}</span>
</div>
{{/if}}
{{#each model.channels as |channel|}}
{{channel-details
channel=channel
provider=model.provider
refresh=(route-action "refreshProvider")
editChannel=(action "editChannel")
test=(action "testChannel")
createRule=(action "createRule")
editRuleWithChannel=(action "editRuleWithChannel")
showError=(action "showError")
}}
{{/each}}
<div class="table-footer">
<div class="pull-right">
{{d-button
id="create-channel"
action=(action "createChannel")
actionParam=model.provider
icon="plus"
title="chat_integration.create_channel"
label="chat_integration.create_channel"
}}
</div>
</div>

View File

@ -1,28 +0,0 @@
<div id="admin-plugin-chat">
<div class="admin-controls">
<div class="admin-controls-chat-providers">
<ul class="nav nav-pills">
{{#each model as |provider|}}
{{nav-item
route="adminPlugins.chat-integration.provider"
routeParam=provider.name
label=(concat "chat_integration.provider." provider.name ".title")
}}
{{/each}}
</ul>
</div>
{{d-button
action=(route-action "showSettings")
icon="cog"
title="chat_integration.settings"
label="chat_integration.settings"
}}
</div>
{{#unless model.totalRows}}
{{i18n "chat_integration.no_providers"}}
{{/unless}}
{{outlet}}
</div>

View File

@ -1,17 +0,0 @@
{{#each provider.channel_parameters as |param|}}
{{#unless param.hidden}}
<span class="field-name">
{{i18n
(concat
"chat_integration.provider."
channel.provider
".param."
param.key
".title"
)
}}:
</span>
<span class="field-value">{{get channel.data param.key}}</span>
<br />
{{/unless}}
{{/each}}

View File

@ -1,77 +0,0 @@
<div class="channel-header">
<div class="pull-right">
{{d-button
action=editChannel
actionParam=channel
icon="pencil-alt"
title="chat_integration.edit_channel"
label="chat_integration.edit_channel"
}}
{{d-button
action=test
actionParam=channel
icon="rocket"
title="chat_integration.test_channel"
label="chat_integration.test_channel"
class="btn-chat-test"
}}
{{d-button
class="cancel delete-channel"
action=(action "deleteChannel")
actionParam=channel
icon="trash-alt"
title="chat_integration.delete_channel"
label="chat_integration.delete_channel"
}}
</div>
<span class="channel-title">
{{#if channel.error_key}}
{{d-button
action=showError
actionParam=channel
class="delete btn-danger"
icon="exclamation-triangle"
}}
{{/if}}
{{channel-data provider=provider channel=channel}}
</span>
</div>
<div class="channel-body">
<table>
<thead>
<tr>
<th>{{i18n "chat_integration.rule_table.filter"}}</th>
<th>{{i18n "chat_integration.rule_table.category"}}</th>
{{#if siteSettings.tagging_enabled}}
<th>{{i18n "chat_integration.rule_table.tags"}}</th>
{{/if}}
<th></th>
</tr>
</thead>
<tbody>
{{#each channel.rules as |rule|}}
{{rule-row rule=rule edit=(action "editRule") refresh=refresh}}
{{/each}}
</tbody>
</table>
</div>
<div class="channel-footer">
<div class="pull-right">
{{d-button
action=createRule
actionParam=channel
icon="plus"
title="chat_integration.create_rule"
label="chat_integration.create_rule"
}}
</div>
</div>

View File

@ -1,45 +0,0 @@
<td>
{{rule.filterName}}
</td>
<td>
{{#if isCategory}}
{{#if rule.category}}
{{category-link rule.category allowUncategorized="true" link="false"}}
{{else}}
{{i18n "chat_integration.all_categories"}}
{{/if}}
{{else if isMention}}
{{i18n "chat_integration.group_mention_template" name=rule.group_name}}
{{else if isMessage}}
{{i18n "chat_integration.group_message_template" name=rule.group_name}}
{{/if}}
</td>
{{#if siteSettings.tagging_enabled}}
<td>
{{#if rule.tags}}
{{rule.tags}}
{{else}}
{{i18n "chat_integration.all_tags"}}
{{/if}}
</td>
{{/if}}
<td>
{{d-button
action=edit
actionParam=rule
icon="pencil-alt"
class="edit"
title="chat_integration.rule_table.edit_rule"
}}
{{d-button
action=(action "delete")
actionParam=rule
icon="far-trash-alt"
class="delete"
title="chat_integration.rule_table.delete_rule"
}}
</td>

View File

@ -66,6 +66,10 @@
table {
width: 100%;
tbody {
border-top: none;
}
tr {
border: none;
}
@ -85,6 +89,8 @@
tr.chat-instructions label {
color: var(--primary-medium);
font-size: var(--font-down-1);
margin-top: 0.5rem;
}
}

View File

@ -143,9 +143,9 @@ acceptance("Chat Integration", function (needs) {
// Press enter
await triggerKeyEvent(
"#chat-integration-edit-channel-modal input",
"#chat-integration-edit-channel-modal",
"keydown",
13
"Enter"
);
assert.notOk(