FEATURE: Improve channel error visibility in the admin panel, stop adding chat integration errors to logs

This commit is contained in:
David Taylor 2018-08-20 12:05:59 +01:00
parent c44ac56d32
commit fc721a1768
12 changed files with 119 additions and 68 deletions

View File

@ -1,6 +1,6 @@
class DiscourseChat::Channel < DiscourseChat::PluginModel class DiscourseChat::Channel < DiscourseChat::PluginModel
# Setup ActiveRecord::Store to use the JSON field to read/write these values # Setup ActiveRecord::Store to use the JSON field to read/write these values
store :value, accessors: [ :provider, :error_key, :data ], coder: JSON store :value, accessors: [ :provider, :error_key, :error_info, :data ], coder: JSON
scope :with_provider, ->(provider) { where("value::json->>'provider'=?", provider) } scope :with_provider, ->(provider) { where("value::json->>'provider'=?", provider) }
scope :with_data_value, ->(key, value) { where("(value::json->>'data')::json->>?=?", key.to_s, value.to_s) } scope :with_data_value, ->(key, value) { where("(value::json->>'data')::json->>?=?", key.to_s, value.to_s) }

View File

@ -1,7 +1,7 @@
require_relative './rule_serializer' require_relative './rule_serializer'
class DiscourseChat::ChannelSerializer < ApplicationSerializer class DiscourseChat::ChannelSerializer < ApplicationSerializer
attributes :id, :provider, :error_key, :data, :rules attributes :id, :provider, :error_key, :error_info, :data, :rules
def rules def rules
object.rules.order_by_precedence.map do |rule| object.rules.order_by_precedence.map do |rule|

View File

@ -86,15 +86,16 @@ module DiscourseChat
else else
channel.update_attribute('error_key', 'chat_integration.channel_exception') channel.update_attribute('error_key', 'chat_integration.channel_exception')
end end
channel.update_attribute('error_info', JSON.pretty_generate(e.try(:info)))
# Log the error # Log the error
Discourse.handle_job_exception(e, # Discourse.handle_job_exception(e,
message: "Triggering notifications failed", # message: "Triggering notifications failed",
extra: { provider_name: provider::PROVIDER_NAME, # extra: { provider_name: provider::PROVIDER_NAME,
channel: rule.channel, # channel: rule.channel,
post_id: post.id, # post_id: post.id,
error_info: e.class == DiscourseChat::ProviderError ? e.info : nil } # error_info: e.class == DiscourseChat::ProviderError ? e.info : nil }
) # )
end end
end end

View File

@ -1,41 +1,48 @@
import { popupAjaxError } from 'discourse/lib/ajax-error'; import { popupAjaxError } from "discourse/lib/ajax-error";
export default Ember.Component.extend({ export default Ember.Component.extend({
classNames: ['channel-details'], classNames: ["channel-details"],
actions: { actions: {
refresh: function(){ refresh: function() {
this.sendAction('refresh'); this.sendAction("refresh");
}, },
delete(channel){ delete(channel) {
bootbox.confirm(I18n.t("chat_integration.channel_delete_confirm"), I18n.t("no_value"), I18n.t("yes_value"), result => { bootbox.confirm(
if (result) { I18n.t("chat_integration.channel_delete_confirm"),
channel.destroyRecord().then(() => { I18n.t("no_value"),
this.send('refresh'); I18n.t("yes_value"),
}).catch(popupAjaxError); result => {
if (result) {
channel
.destroyRecord()
.then(() => {
this.send("refresh");
})
.catch(popupAjaxError);
}
} }
}); );
}, },
edit(channel){ edit(channel) {
this.sendAction('edit', channel); this.sendAction("edit", channel);
}, },
test(channel){ test(channel) {
this.sendAction('test', channel); this.sendAction("test", channel);
}, },
createRule(channel){ createRule(channel) {
this.sendAction('createRule', channel); this.sendAction("createRule", channel);
}, },
editRule(rule){ editRule(rule) {
this.sendAction('editRule', rule, this.get('channel')); this.sendAction("editRule", rule, this.get("channel"));
},
showError(errorKey){
bootbox.alert(I18n.t(errorKey));
}, },
showError(channel) {
this.sendAction("showError", channel);
}
} }
}); });

View File

@ -1,14 +1,14 @@
import showModal from 'discourse/lib/show-modal'; import showModal from "discourse/lib/show-modal";
import computed from "ember-addons/ember-computed-decorators"; import computed from "ember-addons/ember-computed-decorators";
export default Ember.Controller.extend({ export default Ember.Controller.extend({
modalShowing: false, modalShowing: false,
@computed('model.channels') @computed("model.channels")
anyErrors(channels) { anyErrors(channels) {
let anyErrors = false; let anyErrors = false;
channels.forEach((channel) => { channels.forEach(channel => {
if (channel.error_key) { if (channel.error_key) {
anyErrors = true; anyErrors = true;
} }
@ -17,57 +17,78 @@ export default Ember.Controller.extend({
return anyErrors; return anyErrors;
}, },
actions:{ actions: {
createChannel() { createChannel() {
this.set('modalShowing', true); this.set("modalShowing", true);
const model = { const model = {
channel: this.store.createRecord('channel', { provider: this.get('model.provider.id'), data:{} }), channel: this.store.createRecord("channel", {
provider: this.get('model.provider') provider: this.get("model.provider.id"),
data: {}
}),
provider: this.get("model.provider")
}; };
showModal('admin-plugins-chat-edit-channel', { model: model, admin: true }); showModal("admin-plugins-chat-edit-channel", {
model: model,
admin: true
});
}, },
editChannel(channel) { editChannel(channel) {
this.set('modalShowing', true); this.set("modalShowing", true);
const model = { const model = {
channel: channel, channel: channel,
provider: this.get('model.provider') provider: this.get("model.provider")
}; };
showModal('admin-plugins-chat-edit-channel', { model: model, admin: true }); showModal("admin-plugins-chat-edit-channel", {
model: model,
admin: true
});
}, },
testChannel(channel) { testChannel(channel) {
this.set('modalShowing', true); this.set("modalShowing", true);
showModal('admin-plugins-chat-test', { model: { channel: channel }, admin: true }); showModal("admin-plugins-chat-test", {
model: { channel: channel },
admin: true
});
}, },
createRule(channel){ createRule(channel) {
this.set('modalShowing', true); this.set("modalShowing", true);
const model = { const model = {
rule: this.store.createRecord('rule', { channel_id: channel.id }), rule: this.store.createRecord("rule", { channel_id: channel.id }),
channel: channel, channel: channel,
provider: this.get('model.provider'), provider: this.get("model.provider"),
groups: this.get('model.groups') groups: this.get("model.groups")
}; };
showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); showModal("admin-plugins-chat-edit-rule", { model: model, admin: true });
}, },
editRule(rule, channel){ editRule(rule, channel) {
this.set('modalShowing', true); this.set("modalShowing", true);
const model = { const model = {
rule: rule, rule: rule,
channel: channel, channel: channel,
provider: this.get('model.provider'), provider: this.get("model.provider"),
groups: this.get('model.groups') groups: this.get("model.groups")
}; };
showModal('admin-plugins-chat-edit-rule', { model: model, admin: true }); showModal("admin-plugins-chat-edit-rule", { model: model, admin: true });
}, },
showError(channel) {
this.set("modalShowing", true);
showModal("admin-plugins-chat-channel-error", {
model: channel,
admin: true
});
}
} }
}); });

View File

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

View File

@ -14,7 +14,8 @@
edit='editChannel' edit='editChannel'
test='testChannel' test='testChannel'
createRule='createRule' createRule='createRule'
editRule='editRule'}} editRule='editRule'
showError='showError'}}
{{/each}} {{/each}}
<div class="table-footer"> <div class="table-footer">

View File

@ -9,7 +9,7 @@
<span class='channel-title'> <span class='channel-title'>
{{#if channel.error_key}} {{#if channel.error_key}}
{{d-button action="showError" actionParam=channel.error_key class="delete btn-danger" icon="exclamation-triangle"}} {{d-button action="showError" actionParam=channel class="delete btn-danger" icon="exclamation-triangle"}}
{{/if}} {{/if}}
{{channel-data provider=provider channel=channel}} {{channel-data provider=provider channel=channel}}

View File

@ -1,10 +1,9 @@
#admin-plugin-chat { #admin-plugin-chat {
table { table {
margin-top:0; margin-top: 0;
td:last-child { td:last-child {
white-space:nowrap; white-space: nowrap;
} }
td:not(:last-child) { td:not(:last-child) {
@ -18,7 +17,7 @@
div.error { div.error {
font-size: 1.1em; font-size: 1.1em;
font-weight:bold; font-weight: bold;
max-width: 100%; max-width: 100%;
margin-top: 10px; margin-top: 10px;
margin-bottom: 10px; margin-bottom: 10px;
@ -33,7 +32,7 @@
div.channel-header { div.channel-header {
background: $primary-low; background: $primary-low;
padding: 10px; padding: 10px;
overflow:auto; overflow: auto;
.channel-title { .channel-title {
font-size: 1.3em; font-size: 1.3em;
@ -45,7 +44,7 @@
} }
div.channel-footer { div.channel-footer {
overflow:auto; overflow: auto;
} }
} }
} }
@ -54,7 +53,7 @@
#chat_integration_test_modal, #chat_integration_test_modal,
#chat-integration-edit-rule_modal { #chat-integration-edit-rule_modal {
table { table {
width:100%; width: 100%;
tr.input td { tr.input td {
padding-top: 10px; padding-top: 10px;
@ -83,7 +82,7 @@
.tag-chooser { .tag-chooser {
ul.select2-choices { ul.select2-choices {
border: none; border: none;
background:none; background: none;
} }
margin-bottom: 0px; margin-bottom: 0px;
@ -94,3 +93,12 @@
font-weight: bold; font-weight: bold;
} }
} }
#chat_integration_error_modal {
pre {
max-width: 500px;
max-height: 800px;
overflow: scroll;
background: $primary-low;
}
}

View File

@ -9,7 +9,7 @@ en:
settings: "Settings" settings: "Settings"
no_providers: "You need to enable some providers in the plugin settings" no_providers: "You need to enable some providers in the plugin settings"
channels_with_errors: "Some channels for this provider failed last time messages were sent. Click the error icon(s) to learn more." channels_with_errors: "Some channels for this provider failed last time messages were sent. Click the error icon(s) to learn more."
channel_exception: "An unknown error occured when a message was last sent to this channel. Check the site logs for more information." channel_exception: "An unknown error occured when a message was last sent to this channel."
group_mention_template: "Mentions of: @{{name}}" group_mention_template: "Mentions of: @{{name}}"
group_message_template: "Messages to: @{{name}}" group_message_template: "Messages to: @{{name}}"
choose_group: "(choose a group)" choose_group: "(choose a group)"

View File

@ -4,7 +4,6 @@ en:
chat_integration_discourse_username: 'Username of user to act as when fetching content.' chat_integration_discourse_username: 'Username of user to act as when fetching content.'
chat_integration_delay_seconds: 'Number of seconds to wait after post creation before sending chat notitifications' chat_integration_delay_seconds: 'Number of seconds to wait after post creation before sending chat notitifications'
####################################### #######################################
########## SLACK SETTINGS ############# ########## SLACK SETTINGS #############
####################################### #######################################
@ -93,6 +92,8 @@ en:
group_mention_template: "mentions of: @%{name}" group_mention_template: "mentions of: @%{name}"
group_message_template: "messages to: @%{name}" group_message_template: "messages to: @%{name}"
admin_error: "Some chat integration channels have errors. Visit <a href='/admin/plugins/chat'>the chat integration section</a> to find out more."
provider: provider:
####################################### #######################################

View File

@ -22,5 +22,13 @@ after_initialize do
add_admin_route 'chat_integration.menu_title', 'chat' add_admin_route 'chat_integration.menu_title', 'chat'
AdminDashboardData.add_problem_check do
error = false;
DiscourseChat::Channel.find_each do |channel|
error = true unless channel.error_key.blank?
end
I18n.t("chat_integration.admin_error") if error
end
DiscourseChat::Provider.mount_engines DiscourseChat::Provider.mount_engines
end end