WIP webhook row
This commit is contained in:
@@ -3,37 +3,6 @@
|
||||
<div class="col-6">
|
||||
<h2>{{ $t('API') }}</h2>
|
||||
<p>{{ $t('APIText') }}</p>
|
||||
<div class="section">
|
||||
<h3>{{ $t('thirdPartyApps') }}</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
href="https://www.beeminder.com/habitica"
|
||||
>{{ $t('beeminder') }}</a>
|
||||
<br>
|
||||
{{ $t('beeminderDesc') }}
|
||||
</li>
|
||||
<li>
|
||||
<div v-html="$t('chatExtension')">
|
||||
</div>
|
||||
<span>{{ $t('chatExtensionDesc') }}</span>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
target="_blank"
|
||||
:href="`https://oldgods.net/habitica/habitrpg_user_data_display.html?uuid=` + user._id"
|
||||
>{{ $t('dataDisplayTool') }}</a>
|
||||
<br>
|
||||
{{ $t('dataToolDesc') }}
|
||||
</li>
|
||||
<li>
|
||||
<div v-html="$t('otherExtensions')"></div>
|
||||
<span>{{ $t('otherDesc') }}</span>
|
||||
</li>
|
||||
</ul>
|
||||
<hr>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<h2>{{ $t('webhooks') }}</h2>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="input-area">
|
||||
<div>
|
||||
<div
|
||||
v-if="settingsLabel"
|
||||
class="settings-label"
|
||||
@@ -94,4 +94,8 @@ export default {
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
|
||||
.form-group {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -183,7 +183,6 @@ export default {
|
||||
'general',
|
||||
'subscription',
|
||||
'siteData',
|
||||
'api',
|
||||
'promoCode',
|
||||
'transactions',
|
||||
'notifications',
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<webhooks-row />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -43,9 +45,12 @@
|
||||
import UserIdRow from '@/pages/settings/siteDataRows/userIdRow.vue';
|
||||
import UserDataRow from '@/pages/settings/siteDataRows/userDataRow.vue';
|
||||
import ApiRow from '@/pages/settings/siteDataRows/apiRow.vue';
|
||||
import WebhooksRow from '@/pages/settings/siteDataRows/webhooksRow.vue';
|
||||
|
||||
export default {
|
||||
components: { ApiRow, UserDataRow, UserIdRow },
|
||||
components: {
|
||||
WebhooksRow, ApiRow, UserDataRow, UserIdRow,
|
||||
},
|
||||
mounted () {
|
||||
this.$store.dispatch('common:setTitle', {
|
||||
section: this.$t('settings'),
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
<template>
|
||||
<div>
|
||||
<h2
|
||||
v-once
|
||||
>
|
||||
{{ $t("webhooks") }}
|
||||
</h2>
|
||||
<div
|
||||
v-once
|
||||
class="webhooks-info"
|
||||
v-html="$t('webhooksInfo')"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-center webhooks-list">
|
||||
<table class="table table-striped">
|
||||
<tr v-if="user.webhooks.length">
|
||||
<th>{{ $t('webhookURL') }}</th>
|
||||
<th>{{ $t('enabled') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
<tr
|
||||
v-for="(webhook, index) in user.webhooks"
|
||||
:key="webhook.id"
|
||||
>
|
||||
<td style="width: 90%">
|
||||
<div style="width: 440px">
|
||||
<validated-text-input
|
||||
v-model="webhook.url"
|
||||
placeholder="https://habitica-integrations.com/habitica-changes/"
|
||||
:is-valid="isValidUrl(webhook.url)"
|
||||
@blur="saveWebhook(webhook, index)"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td style="vertical-align: middle;">
|
||||
<toggle-switch
|
||||
v-if="!unsaved.includes(index)"
|
||||
v-model="webhook.enabled"
|
||||
@change="updateWebhookEnabled(webhook, index)"
|
||||
/>
|
||||
</td>
|
||||
<td class="menu-column">
|
||||
<b-dropdown
|
||||
v-if="!unsaved.includes(index)"
|
||||
right="right"
|
||||
toggle-class="with-icon"
|
||||
class="ml-2"
|
||||
:no-caret="true"
|
||||
>
|
||||
<template #button-content>
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon inline menuIcon"
|
||||
v-html="icons.menuIcon"
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
<b-dropdown-item
|
||||
class="selectListItem custom-hover--delete"
|
||||
@click="deleteWebhook(webhook, index)"
|
||||
>
|
||||
<span class="with-icon">
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon icon-16 color"
|
||||
v-html="icons.deleteIcon"
|
||||
></span>
|
||||
<span v-once>
|
||||
{{ $t('delete') }}
|
||||
</span>
|
||||
</span>
|
||||
</b-dropdown-item>
|
||||
</b-dropdown>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-secondary d-flex align-items-center"
|
||||
tabindex="0"
|
||||
@click="newUnsavedWebhook()"
|
||||
>
|
||||
<div
|
||||
class="svg-icon icon-10 color"
|
||||
v-html="icons.positive"
|
||||
></div>
|
||||
<div class="ml-75 mr-1">
|
||||
{{ $t('addWebhook') }}
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '~@/assets/scss/colors.scss';
|
||||
|
||||
.webhooks-info {
|
||||
line-height: 1.71;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
.svg-icon.icon-10 {
|
||||
color: $green-10;
|
||||
}
|
||||
|
||||
.menuIcon {
|
||||
width: 4px;
|
||||
height: 1rem;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.custom-hover--delete {
|
||||
--hover-color: #{$maroon-50};
|
||||
--hover-background: #ffb6b83F;
|
||||
}
|
||||
|
||||
.webhooks-list {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 0.5rem;
|
||||
|
||||
tr:first-of-type {
|
||||
th {
|
||||
padding: 0.25rem;
|
||||
border-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 0.5rem !important;
|
||||
|
||||
&:first-of-type {
|
||||
text-align: end;
|
||||
vertical-align: middle;
|
||||
padding-right: 1rem !important;
|
||||
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
color: $gray-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
td.menu-column {
|
||||
width: 2rem;
|
||||
padding-left: 0 !important;
|
||||
padding-right: 0 !important;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import * as validator from 'validator';
|
||||
import { mapState } from '@/libs/store';
|
||||
|
||||
import { InlineSettingMixin } from '../components/inlineSettingMixin';
|
||||
import uuid from '../../../../../common/script/libs/uuid';
|
||||
import positiveIcon from '@/assets/svg/positive.svg';
|
||||
import ToggleSwitch from '@/components/ui/toggleSwitch.vue';
|
||||
import menuIcon from '@/assets/svg/menu.svg';
|
||||
import deleteIcon from '@/assets/svg/delete.svg';
|
||||
import ValidatedTextInput from '@/components/ui/validatedTextInput.vue';
|
||||
|
||||
export default {
|
||||
components: { ValidatedTextInput, ToggleSwitch },
|
||||
mixins: [InlineSettingMixin],
|
||||
data () {
|
||||
return {
|
||||
icons: Object.freeze({
|
||||
positive: positiveIcon,
|
||||
menuIcon,
|
||||
deleteIcon,
|
||||
}),
|
||||
unsaved: [],
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
credentials: 'credentials',
|
||||
}),
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
isValidUrl (url) {
|
||||
return validator.isURL(url, {
|
||||
require_tld: true,
|
||||
require_protocol: true,
|
||||
protocols: ['http', 'https'],
|
||||
});
|
||||
},
|
||||
async newUnsavedWebhook () {
|
||||
const webhookInfo = {
|
||||
id: uuid(),
|
||||
type: 'taskActivity',
|
||||
options: {
|
||||
created: false,
|
||||
updated: false,
|
||||
deleted: false,
|
||||
scored: true,
|
||||
},
|
||||
url: '',
|
||||
enabled: true,
|
||||
};
|
||||
|
||||
this.unsaved.push(
|
||||
this.user.webhooks.push(webhookInfo) - 1,
|
||||
);
|
||||
},
|
||||
async saveWebhook (webhook, index) {
|
||||
if (!this.isValidUrl(webhook.url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.unsaved.includes(index)) {
|
||||
const createdWebhook = await this.$store.dispatch('user:addWebhook', { webhook });
|
||||
|
||||
this.user.webhooks[index] = createdWebhook;
|
||||
this.unsaved = this.unsaved.filter(u => u !== index);
|
||||
} else {
|
||||
const updatedWebhook = await this.$store.dispatch('user:updateWebhook', { webhook });
|
||||
this.user.webhooks[index] = updatedWebhook;
|
||||
}
|
||||
},
|
||||
async updateWebhookEnabled (webhook, index) {
|
||||
if (this.unsaved.includes(index)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const updatedWebhook = await this.$store.dispatch('user:updateWebhook', { webhook });
|
||||
this.user.webhooks[index] = updatedWebhook;
|
||||
},
|
||||
async deleteWebhook (webhook, index) {
|
||||
await this.$store.dispatch('user:deleteWebhook', { webhook });
|
||||
this.user.webhooks.splice(index, 1);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -65,7 +65,7 @@ export async function sleep (store) {
|
||||
}
|
||||
|
||||
export async function addWebhook (store, payload) {
|
||||
const response = await axios.post('/api/v4/user/webhook', payload.webhookInfo);
|
||||
const response = await axios.post('/api/v4/user/webhook', payload.webhook);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
|
||||
@@ -167,9 +167,10 @@
|
||||
"generate": "Generate",
|
||||
"getCodes": "Get Codes",
|
||||
"webhooks": "Webhooks",
|
||||
"webhooksInfo": "Habitica provides webhooks so that when certain actions occur in your account, information can be sent to a script on another website. You can specify those scripts here. Be careful with this feature because specifying an incorrect URL can cause errors or slowness in Habitica. For more information, see the wiki's <a target=\"_blank\" href=\"https://habitica.fandom.com/wiki/Webhooks\">Webhooks</a> page.",
|
||||
"webhooksInfo": "Webhooks provide a way for developers to receive notifications when a particular action is performed, such as scoring or updating a Task, or sending a message in a Group. By creating a webhook, you will be able to listen to changes in Habitica and build apps that respond to these changes.<br><br>For additional information and examples on webhooks, please visit our <a target=\"_blank\" href=\"https://habitica.fandom.com/wiki/Webhooks\">API Docs</a>",
|
||||
"enabled": "Enabled",
|
||||
"webhookURL": "Webhook URL",
|
||||
"addWebhook": "Add Webhook",
|
||||
"invalidUrl": "invalid url",
|
||||
"invalidWebhookId": "the \"id\" parameter should be a valid UUID.",
|
||||
"webhookBooleanOption": "\"<%= option %>\" must be a Boolean value.",
|
||||
|
||||
Reference in New Issue
Block a user