feat: Add event subscription option to webhooks (#4540)
Co-authored-by: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com>
This commit is contained in:
@@ -2,6 +2,10 @@
|
||||
margin-right: var(--space-small);
|
||||
}
|
||||
|
||||
.margin-bottom-small {
|
||||
margin-bottom: var(--space-small);
|
||||
}
|
||||
|
||||
.margin-right-smaller {
|
||||
margin-right: var(--space-smaller);
|
||||
}
|
||||
|
||||
50
app/javascript/dashboard/components/widgets/ShowMore.vue
Normal file
50
app/javascript/dashboard/components/widgets/ShowMore.vue
Normal file
@@ -0,0 +1,50 @@
|
||||
<template>
|
||||
<span>
|
||||
{{ textToBeDisplayed }}
|
||||
<button class="show-more--button" @click="toggleShowMore">
|
||||
{{ buttonLabel }}
|
||||
</button>
|
||||
</span>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
text: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
limit: {
|
||||
type: Number,
|
||||
default: 120,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showMore: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
textToBeDisplayed() {
|
||||
if (this.showMore) {
|
||||
return this.text;
|
||||
}
|
||||
|
||||
return this.text.slice(0, this.limit) + '...';
|
||||
},
|
||||
buttonLabel() {
|
||||
const i18nKey = !this.showMore ? 'SHOW_MORE' : 'SHOW_LESS';
|
||||
return this.$t(`COMPONENTS.SHOW_MORE_BLOCK.${i18nKey}`);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleShowMore() {
|
||||
this.showMore = !this.showMore;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped>
|
||||
.show-more--button {
|
||||
color: var(--w-500);
|
||||
}
|
||||
</style>
|
||||
@@ -2,6 +2,29 @@
|
||||
"INTEGRATION_SETTINGS": {
|
||||
"HEADER": "Integrations",
|
||||
"WEBHOOK": {
|
||||
"SUBSCRIBED_EVENTS": "Subscribed Events",
|
||||
"FORM": {
|
||||
"CANCEL": "Cancel",
|
||||
"DESC": "Webhook events provide you the realtime information about what's happening in your Chatwoot account. Please enter a valid URL to configure a callback.",
|
||||
"SUBSCRIPTIONS": {
|
||||
"LABEL": "Events",
|
||||
"EVENTS": {
|
||||
"CONVERSATION_CREATED": "Conversation Created",
|
||||
"CONVERSATION_STATUS_CHANGED": "Conversation Status Changed",
|
||||
"CONVERSATION_UPDATED": "Conversation Updated",
|
||||
"MESSAGE_CREATED": "Message created",
|
||||
"MESSAGE_UPDATED": "Message updated",
|
||||
"WEBWIDGET_TRIGGERED": "Live chat widget opened by the user"
|
||||
}
|
||||
},
|
||||
"END_POINT": {
|
||||
"LABEL": "Webhook URL",
|
||||
"PLACEHOLDER": "Example: https://example/api/webhook",
|
||||
"ERROR": "Please enter a valid URL"
|
||||
},
|
||||
"EDIT_SUBMIT": "Update webhook",
|
||||
"ADD_SUBMIT": "Create webhook"
|
||||
},
|
||||
"TITLE": "Webhook",
|
||||
"CONFIGURE": "Configure",
|
||||
"HEADER": "Webhook settings",
|
||||
@@ -17,35 +40,16 @@
|
||||
"EDIT": {
|
||||
"BUTTON_TEXT": "Edit",
|
||||
"TITLE": "Edit webhook",
|
||||
"CANCEL": "Cancel",
|
||||
"DESC": "Webhook events provide you the realtime information about what's happening in your Chatwoot account. Please enter a valid URL to configure a callback.",
|
||||
"FORM": {
|
||||
"END_POINT": {
|
||||
"LABEL": "Webhook URL",
|
||||
"PLACEHOLDER": "Example: https://example/api/webhook",
|
||||
"ERROR": "Please enter a valid URL"
|
||||
},
|
||||
"SUBMIT": "Edit webhook"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Webhook URL updated successfully",
|
||||
"SUCCESS_MESSAGE": "Webhook configuration updated successfully",
|
||||
"ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later"
|
||||
}
|
||||
},
|
||||
"ADD": {
|
||||
"CANCEL": "Cancel",
|
||||
"TITLE": "Add new webhook",
|
||||
"DESC": "Webhook events provide you the realtime information about what's happening in your Chatwoot account. Please enter a valid URL to configure a callback.",
|
||||
"FORM": {
|
||||
"END_POINT": {
|
||||
"LABEL": "Webhook URL",
|
||||
"PLACEHOLDER": "Example: https://example/api/webhook",
|
||||
"ERROR": "Please enter a valid URL"
|
||||
},
|
||||
"SUBMIT": "Create webhook"
|
||||
},
|
||||
"API": {
|
||||
"SUCCESS_MESSAGE": "Webhook added successfully",
|
||||
"SUCCESS_MESSAGE": "Webhook configuration added successfully",
|
||||
"ERROR_MESSAGE": "Could not connect to Woot Server, Please try again later"
|
||||
}
|
||||
},
|
||||
@@ -57,16 +61,16 @@
|
||||
},
|
||||
"CONFIRM": {
|
||||
"TITLE": "Confirm Deletion",
|
||||
"MESSAGE": "Are you sure to delete ",
|
||||
"MESSAGE": "Are you sure to delete the webhook? (%{webhookURL})",
|
||||
"YES": "Yes, Delete ",
|
||||
"NO": "No, Keep it"
|
||||
}
|
||||
}
|
||||
},
|
||||
"SLACK": {
|
||||
"HELP_TEXT" : {
|
||||
"HELP_TEXT" : {
|
||||
"TITLE": "Using Slack Integration",
|
||||
"BODY": "<br/><p>Chatwoot will now sync all the incoming conversations into the <b><i>customer-conversations</i></b> channel inside your slack workplace.</p><p>Replying to a conversation thread in <b><i>customer-conversations</i></b> slack channel will create a response back to the customer through chatwoot.</p><p>Start the replies with <b><i>note:</i></b> to create private notes instead of replies.</p><p>If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.</p><p>When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.</p>"
|
||||
"BODY": "<br/><p>Chatwoot will now sync all the incoming conversations into the <b><i>customer-conversations</i></b> channel inside your slack workplace.</p><p>Replying to a conversation thread in <b><i>customer-conversations</i></b> slack channel will create a response back to the customer through chatwoot.</p><p>Start the replies with <b><i>note:</i></b> to create private notes instead of replies.</p><p>If the replier on slack has an agent profile in chatwoot under the same email, the replies will be associated accordingly.</p><p>When the replier doesn't have an associated agent profile, the replies will be made from the bot profile.</p>"
|
||||
}
|
||||
},
|
||||
"DELETE": {
|
||||
|
||||
@@ -127,6 +127,10 @@
|
||||
"BUTTON_TEXT": "Copy",
|
||||
"COPY_SUCCESSFUL": "Code copied to clipboard successfully"
|
||||
},
|
||||
"SHOW_MORE_BLOCK": {
|
||||
"SHOW_MORE": "Show More",
|
||||
"SHOW_LESS": "Show Less"
|
||||
},
|
||||
"FILE_BUBBLE": {
|
||||
"DOWNLOAD": "Download",
|
||||
"UPLOADING": "Uploading..."
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
<template>
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.TITLE')"
|
||||
/>
|
||||
<form class="row" @submit.prevent="editWebhook">
|
||||
<div class="medium-12 columns">
|
||||
<label :class="{ error: $v.endPoint.$error }">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.FORM.END_POINT.LABEL') }}
|
||||
<input
|
||||
v-model.trim="endPoint"
|
||||
type="text"
|
||||
name="endPoint"
|
||||
:placeholder="
|
||||
$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.FORM.END_POINT.PLACEHOLDER')
|
||||
"
|
||||
@input="$v.endPoint.$touch"
|
||||
/>
|
||||
<span v-if="$v.endPoint.$error" class="message">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.FORM.END_POINT.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<div class="medium-12 columns">
|
||||
<woot-button
|
||||
:is-disabled="
|
||||
$v.endPoint.$invalid || uiFlags.updatingItem || endPoint === url
|
||||
"
|
||||
:is-loading="uiFlags.updatingItem"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.FORM.SUBMIT') }}
|
||||
</woot-button>
|
||||
<woot-button class="button clear" @click.prevent="onClose">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.ADD.CANCEL') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { required, url, minLength } from 'vuelidate/lib/validators';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
url: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
onClose: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
alertMessage: '',
|
||||
endPoint: this.url,
|
||||
webhookId: this.id,
|
||||
};
|
||||
},
|
||||
validations: {
|
||||
endPoint: {
|
||||
required,
|
||||
minLength: minLength(7),
|
||||
url,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ uiFlags: 'webhooks/getUIFlags' }),
|
||||
},
|
||||
methods: {
|
||||
resetForm() {
|
||||
this.endPoint = '';
|
||||
this.$v.endPoint.$reset();
|
||||
},
|
||||
async editWebhook() {
|
||||
try {
|
||||
await this.$store.dispatch('webhooks/update', {
|
||||
webhook: { url: this.endPoint },
|
||||
id: this.webhookId,
|
||||
});
|
||||
this.alertMessage = this.$t(
|
||||
'INTEGRATION_SETTINGS.WEBHOOK.EDIT.API.SUCCESS_MESSAGE'
|
||||
);
|
||||
this.resetForm();
|
||||
this.onClose();
|
||||
} catch (error) {
|
||||
this.alertMessage =
|
||||
error.response.data.message ||
|
||||
this.$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.API.ERROR_MESSAGE');
|
||||
} finally {
|
||||
this.showAlert(this.alertMessage);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,121 +0,0 @@
|
||||
<template>
|
||||
<modal :show.sync="show" :on-close="onClose" :close-on-backdrop-click="false">
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('INTEGRATION_SETTINGS.WEBHOOK.ADD.TITLE')"
|
||||
:header-content="
|
||||
useInstallationName(
|
||||
$t('INTEGRATION_SETTINGS.WEBHOOK.ADD.DESC'),
|
||||
globalConfig.installationName
|
||||
)
|
||||
"
|
||||
/>
|
||||
<form class="row" @submit.prevent="addWebhook">
|
||||
<div class="medium-12 columns">
|
||||
<label :class="{ error: $v.endPoint.$error }">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.ADD.FORM.END_POINT.LABEL') }}
|
||||
<input
|
||||
v-model.trim="endPoint"
|
||||
type="text"
|
||||
name="endPoint"
|
||||
:placeholder="
|
||||
$t(
|
||||
'INTEGRATION_SETTINGS.WEBHOOK.ADD.FORM.END_POINT.PLACEHOLDER'
|
||||
)
|
||||
"
|
||||
@input="$v.endPoint.$touch"
|
||||
/>
|
||||
<span v-if="$v.endPoint.$error" class="message">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.ADD.FORM.END_POINT.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<div class="medium-12 columns">
|
||||
<woot-button
|
||||
:disabled="$v.endPoint.$invalid || addWebHook.showLoading"
|
||||
:is-loading="addWebHook.showLoading"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.ADD.FORM.SUBMIT') }}
|
||||
</woot-button>
|
||||
<woot-button class="button clear" @click.prevent="onClose">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.ADD.CANCEL') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { required, url, minLength } from 'vuelidate/lib/validators';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import Modal from '../../../../components/Modal';
|
||||
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
mixins: [alertMixin, globalConfigMixin],
|
||||
props: {
|
||||
onClose: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
endPoint: '',
|
||||
addWebHook: {
|
||||
showAlert: false,
|
||||
showLoading: false,
|
||||
},
|
||||
show: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ globalConfig: 'globalConfig/get' }),
|
||||
},
|
||||
validations: {
|
||||
endPoint: {
|
||||
required,
|
||||
minLength: minLength(7),
|
||||
url,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
resetForm() {
|
||||
this.endPoint = '';
|
||||
this.$v.endPoint.$reset();
|
||||
},
|
||||
async addWebhook() {
|
||||
this.addWebHook.showLoading = true;
|
||||
|
||||
try {
|
||||
await this.$store.dispatch('webhooks/create', {
|
||||
webhook: { url: this.endPoint },
|
||||
});
|
||||
this.addWebHook.showLoading = false;
|
||||
|
||||
this.addWebHook.message = this.$t(
|
||||
'INTEGRATION_SETTINGS.WEBHOOK.ADD.API.SUCCESS_MESSAGE'
|
||||
);
|
||||
this.resetForm();
|
||||
this.onClose();
|
||||
} catch (error) {
|
||||
this.addWebHook.showLoading = false;
|
||||
this.addWebHook.message =
|
||||
error.response.data.message ||
|
||||
this.$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.API.ERROR_MESSAGE');
|
||||
} finally {
|
||||
this.addWebHook.showLoading = false;
|
||||
this.showAlert(this.addWebHook.message);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.TITLE')"
|
||||
/>
|
||||
<webhook-form
|
||||
:value="value"
|
||||
:is-submitting="uiFlags.updatingItem"
|
||||
:submit-label="$t('INTEGRATION_SETTINGS.WEBHOOK.FORM.EDIT_SUBMIT')"
|
||||
@submit="onSubmit"
|
||||
@cancel="onClose"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
import WebhookForm from './WebhookForm.vue';
|
||||
|
||||
export default {
|
||||
components: { WebhookForm },
|
||||
mixins: [alertMixin],
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
id: {
|
||||
type: [Number, String],
|
||||
required: true,
|
||||
},
|
||||
onClose: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({ uiFlags: 'webhooks/getUIFlags' }),
|
||||
},
|
||||
methods: {
|
||||
async onSubmit(webhook) {
|
||||
try {
|
||||
await this.$store.dispatch('webhooks/update', {
|
||||
webhook,
|
||||
id: this.id,
|
||||
});
|
||||
this.showAlert(
|
||||
this.$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.API.SUCCESS_MESSAGE')
|
||||
);
|
||||
this.onClose();
|
||||
} catch (error) {
|
||||
const alertMessage =
|
||||
error.response.data.message ||
|
||||
this.$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.API.ERROR_MESSAGE');
|
||||
this.showAlert(alertMessage);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -4,7 +4,7 @@
|
||||
color-scheme="success"
|
||||
class-names="button--fixed-right-top"
|
||||
icon="add-circle"
|
||||
@click="openAddPopup()"
|
||||
@click="openAddPopup"
|
||||
>
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.HEADER_BTN_TXT') }}
|
||||
</woot-button>
|
||||
@@ -37,35 +37,14 @@
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="(webHookItem, index) in records" :key="webHookItem.id">
|
||||
<td class="webhook-link">
|
||||
{{ webHookItem.url }}
|
||||
</td>
|
||||
<td class="button-wrapper">
|
||||
<woot-button
|
||||
v-tooltip.top="
|
||||
$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.BUTTON_TEXT')
|
||||
"
|
||||
variant="smooth"
|
||||
size="tiny"
|
||||
color-scheme="secondary"
|
||||
icon="edit"
|
||||
@click="openEditPopup(webHookItem)"
|
||||
>
|
||||
</woot-button>
|
||||
<woot-button
|
||||
v-tooltip.top="
|
||||
$t('INTEGRATION_SETTINGS.WEBHOOK.DELETE.BUTTON_TEXT')
|
||||
"
|
||||
variant="smooth"
|
||||
color-scheme="alert"
|
||||
size="tiny"
|
||||
icon="dismiss-circle"
|
||||
@click="openDeletePopup(webHookItem, index)"
|
||||
>
|
||||
</woot-button>
|
||||
</td>
|
||||
</tr>
|
||||
<webhook-row
|
||||
v-for="(webHookItem, index) in records"
|
||||
:key="webHookItem.id"
|
||||
:index="index"
|
||||
:webhook="webHookItem"
|
||||
@edit="openEditPopup"
|
||||
@delete="openDeletePopup"
|
||||
/>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -83,24 +62,27 @@
|
||||
</div>
|
||||
|
||||
<woot-modal :show.sync="showAddPopup" :on-close="hideAddPopup">
|
||||
<new-webhook :on-close="hideAddPopup" />
|
||||
<new-webhook v-if="showAddPopup" :on-close="hideAddPopup" />
|
||||
</woot-modal>
|
||||
|
||||
<woot-modal :show.sync="showEditPopup" :on-close="hideEditPopup">
|
||||
<edit-webhook
|
||||
v-if="showEditPopup"
|
||||
:id="selectedWebHook.id"
|
||||
:url="selectedWebHook.url"
|
||||
:value="selectedWebHook"
|
||||
:on-close="hideEditPopup"
|
||||
/>
|
||||
</woot-modal>
|
||||
|
||||
<woot-delete-modal
|
||||
:show.sync="showDeleteConfirmationPopup"
|
||||
:on-close="closeDeletePopup"
|
||||
:on-confirm="confirmDeletion"
|
||||
:title="$t('INTEGRATION_SETTINGS.WEBHOOK.DELETE.CONFIRM.TITLE')"
|
||||
:message="$t('INTEGRATION_SETTINGS.WEBHOOK.DELETE.CONFIRM.MESSAGE')"
|
||||
:message="
|
||||
$t('INTEGRATION_SETTINGS.WEBHOOK.DELETE.CONFIRM.MESSAGE', {
|
||||
webhookURL: selectedWebHook.url,
|
||||
})
|
||||
"
|
||||
:confirm-text="$t('INTEGRATION_SETTINGS.WEBHOOK.DELETE.CONFIRM.YES')"
|
||||
:reject-text="$t('INTEGRATION_SETTINGS.WEBHOOK.DELETE.CONFIRM.NO')"
|
||||
/>
|
||||
@@ -112,11 +94,13 @@ import NewWebhook from './NewWebHook';
|
||||
import EditWebhook from './EditWebHook';
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||
import WebhookRow from './WebhookRow';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NewWebhook,
|
||||
EditWebhook,
|
||||
WebhookRow,
|
||||
},
|
||||
mixins: [alertMixin, globalConfigMixin],
|
||||
data() {
|
||||
@@ -179,11 +163,3 @@ export default {
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.webhook-link {
|
||||
word-break: break-word;
|
||||
}
|
||||
.button-wrapper button:nth-child(2) {
|
||||
margin-left: var(--space-normal);
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="column content-box">
|
||||
<woot-modal-header
|
||||
:header-title="$t('INTEGRATION_SETTINGS.WEBHOOK.ADD.TITLE')"
|
||||
:header-content="
|
||||
useInstallationName(
|
||||
$t('INTEGRATION_SETTINGS.WEBHOOK.FORM.DESC'),
|
||||
globalConfig.installationName
|
||||
)
|
||||
"
|
||||
/>
|
||||
<webhook-form
|
||||
:is-submitting="uiFlags.creatingItem"
|
||||
:submit-label="$t('INTEGRATION_SETTINGS.WEBHOOK.FORM.ADD_SUBMIT')"
|
||||
@submit="onSubmit"
|
||||
@cancel="onClose"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import alertMixin from 'shared/mixins/alertMixin';
|
||||
import globalConfigMixin from 'shared/mixins/globalConfigMixin';
|
||||
import { mapGetters } from 'vuex';
|
||||
import WebhookForm from './WebhookForm.vue';
|
||||
|
||||
export default {
|
||||
components: { WebhookForm },
|
||||
mixins: [alertMixin, globalConfigMixin],
|
||||
props: {
|
||||
onClose: {
|
||||
type: Function,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters({
|
||||
globalConfig: 'globalConfig/get',
|
||||
uiFlags: 'webhooks/getUIFlags',
|
||||
}),
|
||||
},
|
||||
methods: {
|
||||
async onSubmit(webhook) {
|
||||
try {
|
||||
await this.$store.dispatch('webhooks/create', { webhook });
|
||||
this.showAlert(
|
||||
this.$t('INTEGRATION_SETTINGS.WEBHOOK.ADD.API.SUCCESS_MESSAGE')
|
||||
);
|
||||
this.onClose();
|
||||
} catch (error) {
|
||||
const message =
|
||||
error.response.data.message ||
|
||||
this.$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.API.ERROR_MESSAGE');
|
||||
this.showAlert(message);
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,108 @@
|
||||
<template>
|
||||
<form class="row" @submit.prevent="onSubmit">
|
||||
<div class="medium-12 columns">
|
||||
<label :class="{ error: $v.url.$error }">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.END_POINT.LABEL') }}
|
||||
<input
|
||||
v-model.trim="url"
|
||||
type="text"
|
||||
name="url"
|
||||
:placeholder="
|
||||
$t('INTEGRATION_SETTINGS.WEBHOOK.FORM.END_POINT.PLACEHOLDER')
|
||||
"
|
||||
@input="$v.url.$touch"
|
||||
/>
|
||||
<span v-if="$v.url.$error" class="message">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.END_POINT.ERROR') }}
|
||||
</span>
|
||||
</label>
|
||||
<label :class="{ error: $v.url.$error }" class="margin-bottom-small">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.SUBSCRIPTIONS.LABEL') }}
|
||||
</label>
|
||||
<div v-for="event in supportedWebhookEvents" :key="event">
|
||||
<input
|
||||
:id="event"
|
||||
v-model="subscriptions"
|
||||
type="checkbox"
|
||||
:value="event"
|
||||
name="subscriptions"
|
||||
class="margin-right-small"
|
||||
/>
|
||||
<span class="fs-small">
|
||||
{{ `${getEventLabel(event)} (${event})` }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<div class="medium-12 columns">
|
||||
<woot-button
|
||||
:disabled="$v.$invalid || isSubmitting"
|
||||
:is-loading="isSubmitting"
|
||||
>
|
||||
{{ submitLabel }}
|
||||
</woot-button>
|
||||
<woot-button class="button clear" @click.prevent="$emit('cancel')">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.FORM.CANCEL') }}
|
||||
</woot-button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { required, url, minLength } from 'vuelidate/lib/validators';
|
||||
import webhookMixin from './webhookMixin';
|
||||
|
||||
const SUPPORTED_WEBHOOK_EVENTS = [
|
||||
'conversation_created',
|
||||
'conversation_status_changed',
|
||||
'conversation_updated',
|
||||
'message_created',
|
||||
'message_updated',
|
||||
'webwidget_triggered',
|
||||
];
|
||||
|
||||
export default {
|
||||
mixins: [webhookMixin],
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
default: () => ({}),
|
||||
},
|
||||
isSubmitting: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
submitLabel: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
validations: {
|
||||
url: {
|
||||
required,
|
||||
minLength: minLength(7),
|
||||
url,
|
||||
},
|
||||
subscriptions: {
|
||||
required,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
url: this.value.url || '',
|
||||
subscriptions: this.value.subscriptions || [],
|
||||
supportedWebhookEvents: SUPPORTED_WEBHOOK_EVENTS,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onSubmit() {
|
||||
this.$emit('submit', {
|
||||
url: this.url,
|
||||
subscriptions: this.subscriptions,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,83 @@
|
||||
<template>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="webhook--link">{{ webhook.url }}</div>
|
||||
<span class="webhook--subscribed-events">
|
||||
<span class="webhook--subscribed-label">
|
||||
{{ $t('INTEGRATION_SETTINGS.WEBHOOK.SUBSCRIBED_EVENTS') }}:
|
||||
</span>
|
||||
<show-more :text="subscribedEvents" :limit="60" />
|
||||
</span>
|
||||
</td>
|
||||
<td class="button-wrapper">
|
||||
<woot-button
|
||||
v-tooltip.top="$t('INTEGRATION_SETTINGS.WEBHOOK.EDIT.BUTTON_TEXT')"
|
||||
variant="smooth"
|
||||
size="tiny"
|
||||
color-scheme="secondary"
|
||||
icon="edit"
|
||||
@click="$emit('edit', webhook)"
|
||||
>
|
||||
</woot-button>
|
||||
<woot-button
|
||||
v-tooltip.top="$t('INTEGRATION_SETTINGS.WEBHOOK.DELETE.BUTTON_TEXT')"
|
||||
variant="smooth"
|
||||
color-scheme="alert"
|
||||
size="tiny"
|
||||
icon="dismiss-circle"
|
||||
@click="$emit('delete', webhook, index)"
|
||||
>
|
||||
</woot-button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
<script>
|
||||
import webhookMixin from './webhookMixin';
|
||||
import ShowMore from 'dashboard/components/widgets/ShowMore';
|
||||
|
||||
export default {
|
||||
components: { ShowMore },
|
||||
mixins: [webhookMixin],
|
||||
props: {
|
||||
webhook: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
index: {
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
subscribedEvents() {
|
||||
const { subscriptions } = this.webhook;
|
||||
return subscriptions.map(event => this.getEventLabel(event)).join(', ');
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style scoped lang="scss">
|
||||
.webhook--link {
|
||||
color: var(--s-700);
|
||||
font-weight: var(--font-weight-medium);
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.webhook--subscribed-events {
|
||||
color: var(--s-500);
|
||||
font-size: var(--font-size-mini);
|
||||
}
|
||||
|
||||
.webhook--subscribed-label {
|
||||
font-weight: var(--font-weight-medium);
|
||||
}
|
||||
|
||||
.button-wrapper {
|
||||
max-width: var(--space-mega);
|
||||
min-width: auto;
|
||||
|
||||
button:nth-child(2) {
|
||||
margin-left: var(--space-normal);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,26 @@
|
||||
import { createWrapper } from '@vue/test-utils';
|
||||
import webhookMixin from '../webhookMixin';
|
||||
import Vue from 'vue';
|
||||
|
||||
describe('webhookMixin', () => {
|
||||
describe('#getEventLabel', () => {
|
||||
it('returns correct i18n translation:', () => {
|
||||
const Component = {
|
||||
render() {},
|
||||
title: 'WebhookComponent',
|
||||
mixins: [webhookMixin],
|
||||
methods: {
|
||||
$t(text) {
|
||||
return text;
|
||||
},
|
||||
},
|
||||
};
|
||||
const Constructor = Vue.extend(Component);
|
||||
const vm = new Constructor().$mount();
|
||||
const wrapper = createWrapper(vm);
|
||||
expect(wrapper.vm.getEventLabel('message_created')).toEqual(
|
||||
`INTEGRATION_SETTINGS.WEBHOOK.FORM.SUBSCRIPTIONS.EVENTS.MESSAGE_CREATED`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
export default {
|
||||
methods: {
|
||||
getEventLabel(event) {
|
||||
const eventName = event.toUpperCase();
|
||||
return this.$t(
|
||||
`INTEGRATION_SETTINGS.WEBHOOK.FORM.SUBSCRIPTIONS.EVENTS.${eventName}`
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import Index from './Index';
|
||||
import SettingsContent from '../Wrapper';
|
||||
import Webhook from './Webhook';
|
||||
import Webhook from './Webhooks/Index';
|
||||
import ShowIntegration from './ShowIntegration';
|
||||
import { frontendURL } from '../../../../helper/URLHelper';
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ const state = {
|
||||
|
||||
export const getters = {
|
||||
getWebhooks(_state) {
|
||||
return _state.records;
|
||||
return _state.records.sort((w1, w2) => w1.id - w2.id);
|
||||
},
|
||||
getUIFlags(_state) {
|
||||
return _state.uiFlags;
|
||||
|
||||
Reference in New Issue
Block a user