refactor webhook ui to use save/cancel buttons
This commit is contained in:
@@ -10,8 +10,8 @@
|
||||
<div
|
||||
class="input-group"
|
||||
:class="{
|
||||
'is-valid': wasChanged && isValid,
|
||||
'is-invalid': wasChanged && !isValid
|
||||
'is-valid': canChangeClasses && isValid,
|
||||
'is-invalid': canChangeClasses && !isValid
|
||||
}"
|
||||
>
|
||||
<input
|
||||
@@ -19,9 +19,11 @@
|
||||
class="form-control"
|
||||
type="text"
|
||||
:class="{
|
||||
'is-invalid input-invalid': wasChanged && !isValid,
|
||||
'is-valid input-valid': wasChanged && isValid
|
||||
'is-invalid input-invalid': canChangeClasses && !isValid,
|
||||
'is-valid input-valid': canChangeClasses && isValid
|
||||
}"
|
||||
:readonly="readonly"
|
||||
:aria-readonly="readonly"
|
||||
|
||||
:placeholder="placeholder"
|
||||
@keyup="handleChange"
|
||||
@@ -56,6 +58,10 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
readonly: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
settingsLabel: {
|
||||
type: String,
|
||||
},
|
||||
@@ -72,6 +78,11 @@ export default {
|
||||
wasChanged: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
canChangeClasses () {
|
||||
return !this.readonly && this.wasChanged;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleChange ({ target: { value } }) {
|
||||
this.wasChanged = true;
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
}
|
||||
|
||||
.settings-content {
|
||||
flex: 0 0 684px;
|
||||
flex: 0 0 732px;
|
||||
max-width: unset;
|
||||
|
||||
::v-deep {
|
||||
|
||||
@@ -14,27 +14,43 @@
|
||||
|
||||
<div
|
||||
class="d-flex justify-content-center webhooks-list"
|
||||
:class="{'webhooks-exists': Boolean(user.webhooks.length)}"
|
||||
:class="{'webhooks-exists': Boolean(webhooks.length)}"
|
||||
>
|
||||
<table class="table table-striped">
|
||||
<tr v-if="user.webhooks.length">
|
||||
<tr v-if="webhooks.length">
|
||||
<th>{{ $t('webhookURL') }}</th>
|
||||
<th>{{ $t('enabled') }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
<tr
|
||||
v-for="(webhook, index) in user.webhooks"
|
||||
v-for="(webhook, index) in 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)"
|
||||
/>
|
||||
<td style="width: 588px">
|
||||
<div class="d-flex align-items-center">
|
||||
<div style="width: 440px">
|
||||
<validated-text-input
|
||||
v-model="webhook.url"
|
||||
:placeholder="$t('webhookURL')"
|
||||
:is-valid="isValidUrl(webhook.url)"
|
||||
:readonly="!unsaved.includes(index)"
|
||||
/>
|
||||
</div>
|
||||
<template v-if="unsaved.includes(index)">
|
||||
<button
|
||||
class="btn btn-primary ml-2"
|
||||
@click="saveWebhook(webhook, index)"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
<a
|
||||
class="edit-link ml-3"
|
||||
@click.prevent="cancelWebhookChanges(webhook, index)"
|
||||
>
|
||||
{{ $t('cancel') }}
|
||||
</a>
|
||||
</template>
|
||||
</div>
|
||||
</td>
|
||||
<td style="vertical-align: middle;">
|
||||
@@ -60,6 +76,21 @@
|
||||
>
|
||||
</span>
|
||||
</template>
|
||||
<b-dropdown-item
|
||||
class="selectListItem"
|
||||
@click="editWebhook(webhook, index)"
|
||||
>
|
||||
<span class="with-icon">
|
||||
<span
|
||||
v-once
|
||||
class="svg-icon icon-16 color"
|
||||
v-html="icons.editIcon"
|
||||
></span>
|
||||
<span v-once>
|
||||
{{ $t('edit') }}
|
||||
</span>
|
||||
</span>
|
||||
</b-dropdown-item>
|
||||
<b-dropdown-item
|
||||
class="selectListItem custom-hover--delete"
|
||||
@click="deleteWebhook(webhook, index)"
|
||||
@@ -81,11 +112,11 @@
|
||||
<tr>
|
||||
<td
|
||||
colspan="3"
|
||||
:class="{'webhooks-empty': !Boolean(user.webhooks.length)}"
|
||||
:class="{'webhooks-empty': !Boolean(webhooks.length)}"
|
||||
>
|
||||
<button
|
||||
class="btn btn-secondary d-flex align-items-center new-webhook-btn"
|
||||
:class="{'webhooks-exists': Boolean(user.webhooks.length)}"
|
||||
:class="{'webhooks-exists': Boolean(webhooks.length)}"
|
||||
tabindex="0"
|
||||
@click="newUnsavedWebhook()"
|
||||
>
|
||||
@@ -145,10 +176,14 @@
|
||||
vertical-align: middle;
|
||||
padding-right: 1rem !important;
|
||||
|
||||
font-weight: bold;
|
||||
line-height: 1.71;
|
||||
color: $gray-50;
|
||||
}
|
||||
|
||||
&:not(:first-of-type) {
|
||||
padding-right: 0 !important;
|
||||
padding-left: 0 !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,6 +217,7 @@ 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';
|
||||
import editIcon from '@/assets/svg/edit.svg';
|
||||
|
||||
export default {
|
||||
components: { ValidatedTextInput, ToggleSwitch },
|
||||
@@ -192,10 +228,15 @@ export default {
|
||||
positive: positiveIcon,
|
||||
menuIcon,
|
||||
deleteIcon,
|
||||
editIcon,
|
||||
}),
|
||||
webhooks: [], // view copy of state
|
||||
unsaved: [],
|
||||
};
|
||||
},
|
||||
mounted () {
|
||||
this.setWebhooksViewCopy();
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
user: 'user.data',
|
||||
@@ -203,7 +244,6 @@ export default {
|
||||
}),
|
||||
|
||||
},
|
||||
|
||||
methods: {
|
||||
isValidUrl (url) {
|
||||
return validator.isURL(url, {
|
||||
@@ -227,23 +267,36 @@ export default {
|
||||
};
|
||||
|
||||
this.unsaved.push(
|
||||
this.user.webhooks.push(webhookInfo) - 1,
|
||||
this.webhooks.push(webhookInfo) - 1,
|
||||
);
|
||||
},
|
||||
cancelWebhookChanges (webhook, index) {
|
||||
if (this.unsaved.includes(index)) {
|
||||
this.unsaved = this.unsaved.filter(i => i !== index);
|
||||
}
|
||||
|
||||
if (this.user.webhooks[index]) {
|
||||
this.webhooks[index] = this.user.webhooks[index];
|
||||
} else {
|
||||
this.webhooks.splice(index, 1);
|
||||
}
|
||||
},
|
||||
async saveWebhook (webhook, index) {
|
||||
if (!this.isValidUrl(webhook.url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.unsaved.includes(index)) {
|
||||
const webhookId = webhook.id;
|
||||
|
||||
if (this.user.webhooks.every(w => w.id !== webhookId)) {
|
||||
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;
|
||||
}
|
||||
this.cancelWebhookChanges(webhook, index);
|
||||
},
|
||||
async updateWebhookEnabled (webhook, index) {
|
||||
if (this.unsaved.includes(index)) {
|
||||
@@ -253,9 +306,16 @@ export default {
|
||||
const updatedWebhook = await this.$store.dispatch('user:updateWebhook', { webhook });
|
||||
this.user.webhooks[index] = updatedWebhook;
|
||||
},
|
||||
async editWebhook (webhook, index) {
|
||||
this.unsaved.push(index);
|
||||
},
|
||||
async deleteWebhook (webhook, index) {
|
||||
await this.$store.dispatch('user:deleteWebhook', { webhook });
|
||||
this.user.webhooks.splice(index, 1);
|
||||
this.setWebhooksViewCopy();
|
||||
},
|
||||
setWebhooksViewCopy () {
|
||||
this.webhooks = [...this.user.webhooks];
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user