summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaksim Sukharev <antreesy.web@gmail.com>2023-08-10 12:08:17 +0200
committerJoas Schilling <coding@schilljs.com>2023-08-10 16:26:12 +0200
commit6169672f469c74ec254aa0f8313e33c974fa45f6 (patch)
treeb9be7d2a7fb8e0b19d7cd93e745146661c639d8b
parent5e10ea4dce0a9df9a474b661716004fe3ea68f19 (diff)
add frontend support for listing bots in admin settings
Signed-off-by: Maksim Sukharev <antreesy.web@gmail.com>
-rw-r--r--src/components/AdminSettings/BotsSettings.vue197
-rw-r--r--src/components/ConversationSettings/BotsSettings.vue10
-rw-r--r--src/constants.js2
-rw-r--r--src/services/botsService.js31
-rw-r--r--src/views/AdminSettings.vue3
5 files changed, 216 insertions, 27 deletions
diff --git a/src/components/AdminSettings/BotsSettings.vue b/src/components/AdminSettings/BotsSettings.vue
new file mode 100644
index 000000000..1f1317807
--- /dev/null
+++ b/src/components/AdminSettings/BotsSettings.vue
@@ -0,0 +1,197 @@
+<!--
+ - @copyright Copyright (c) 2023 Maksim Sukharev <antreesy.web@gmail.com>
+ -
+ - @author Maksim Sukharev <antreesy.web@gmail.com>
+ -
+ - @license AGPL-3.0-or-later
+ -
+ - This program is free software: you can redistribute it and/or modify
+ - it under the terms of the GNU Affero General Public License as
+ - published by the Free Software Foundation, either version 3 of the
+ - License, or (at your option) any later version.
+ -
+ - This program is distributed in the hope that it will be useful,
+ - but WITHOUT ANY WARRANTY; without even the implied warranty of
+ - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ - GNU Affero General Public License for more details.
+ -
+ - You should have received a copy of the GNU Affero General Public License
+ - along with this program. If not, see <http://www.gnu.org/licenses/>.
+ -
+ -->
+
+<template>
+ <section id="bots_settings" class="bots-settings section">
+ <h2>{{ t('spreed', 'Bots settings') }}</h2>
+
+ <p class="settings-hint">
+ {{ botsSettingsDescription }}
+ </p>
+
+ <ul v-if="bots.length" class="bots-settings__list">
+ <li class="bots-settings__item bots-settings__item--head">
+ <div class="state">
+ {{ t('spreed', 'State') }}
+ </div>
+ <div class="name">
+ {{ t('spreed', 'Name') }}
+ </div>
+ <div class="description">
+ {{ t('spreed', 'Description') }}
+ </div>
+ <div class="last-error">
+ {{ t('spreed', 'Last error') }}
+ </div>
+ <div class="error-count">
+ {{ t('spreed', 'Total errors count') }}
+ </div>
+ </li>
+
+ <li v-for="bot in botsExtended"
+ :key="bot.id"
+ class="bots-settings__item">
+ <div class="state">
+ <span class="state__icon"
+ :aria-label="bot.state_icon_label"
+ :title="bot.state_icon_label">
+ <component :is="bot.state_icon_component"
+ :fill-color="bot.state_icon_color" />
+ </span>
+ </div>
+ <div class="name bold">
+ {{ bot.name }}
+ </div>
+ <div class="description">
+ {{ bot.description }}
+ </div>
+ <div :id="`last_error_bot_${bot.id}`" class="last-error">
+ <NcPopover v-if="bot.last_error_message"
+ :container="`#last_error_bot_${bot.id}`"
+ :focus-trap="false">
+ <template #trigger>
+ <NcButton type="error" :aria-label="bot.last_error_message">
+ {{ bot.last_error_date }}
+ </NcButton>
+ </template>
+ <div class="last-error__popover-content">
+ {{ bot.last_error_message }}
+ </div>
+ </NcPopover>
+ </div>
+ <div class="error-count">
+ <span v-if="bot.error_count">
+ {{ bot.error_count }}
+ </span>
+ </div>
+ </li>
+ </ul>
+ </section>
+</template>
+
+<script>
+import Cancel from 'vue-material-design-icons/Cancel.vue'
+import Check from 'vue-material-design-icons/Check.vue'
+import Lock from 'vue-material-design-icons/Lock.vue'
+
+import moment from '@nextcloud/moment'
+
+import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
+import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
+import NcPopover from '@nextcloud/vue/dist/Components/NcPopover.js'
+
+import { BOT } from '../../constants.js'
+import { getAllBots } from '../../services/botsService.js'
+
+export default {
+ name: 'BotsSettings',
+
+ components: {
+ NcPopover,
+ NcButton,
+ NcCheckboxRadioSwitch,
+ },
+
+ data() {
+ return {
+ loading: true,
+ bots: [],
+ }
+ },
+
+ computed: {
+ botsSettingsDescription() {
+ return this.bots.length
+ ? t('spreed', 'The following bots can be enabled. Reach out to your administration to get more bots installed on this server.')
+ : t('spreed', 'No bots are installed on this server. Reach out to your administration to get bots installed on this server.')
+ },
+
+ botsExtended() {
+ return this.bots.map(bot => ({
+ ...bot,
+ ...this.getStateIcon(bot.state),
+ description: bot.description ?? t('spreed', 'Description is not provided'),
+ last_error_date: bot.last_error_date ? moment(bot.last_error_date * 1000).format('ll LTS') : '---',
+ }))
+ },
+ },
+
+ async mounted() {
+ this.loading = true
+ try {
+ const response = await getAllBots()
+ this.bots = response.data.ocs.data
+ } catch (error) {
+ console.error(error)
+ }
+ this.loading = false
+ },
+
+ methods: {
+ getStateIcon(state) {
+ switch (state) {
+ case BOT.STATE.NO_SETUP:
+ return { state_icon_component: Lock, state_icon_label: t('spreed', 'Locked for moderators'), state_icon_color: 'var(--color-placeholder-dark)' }
+ case BOT.STATE.ENABLED:
+ return { state_icon_component: Check, state_icon_label: t('spreed', 'Enabled'), state_icon_color: 'var(--color-success)' }
+ case BOT.STATE.DISABLED:
+ default:
+ return { state_icon_component: Cancel, state_icon_label: t('spreed', 'Disabled'), state_icon_color: 'var(--color-placeholder-dark)' }
+ }
+ },
+ },
+}
+</script>
+
+<style scoped lang="scss">
+h3 {
+ margin-top: 24px;
+ font-weight: 600;
+}
+
+.bots-settings {
+ &__item {
+ display: grid;
+ grid-template-columns: minmax(50px, 100px) 1fr 2fr minmax(100px, 250px) minmax(50px, 100px);
+ grid-column-gap: 5px;
+
+ &:not(:last-child) {
+ margin-bottom: 10px;
+ }
+
+ &--head {
+ padding-bottom: 5px;
+ border-bottom: 1px solid var(--color-border);
+ font-weight: bold;
+ }
+
+ .bold {
+ font-weight: bold;
+ }
+
+ .last-error__popover-content {
+ margin: calc(var(--default-grid-baseline) * 2);
+ }
+ }
+}
+
+</style>
diff --git a/src/components/ConversationSettings/BotsSettings.vue b/src/components/ConversationSettings/BotsSettings.vue
index 4902171d5..6732a5404 100644
--- a/src/components/ConversationSettings/BotsSettings.vue
+++ b/src/components/ConversationSettings/BotsSettings.vue
@@ -40,7 +40,7 @@
<div v-if="isLoading[bot.id]" class="bots-settings__item-loader icon icon-loading-small" />
<NcButton class="bots-settings__item-button"
:type="bot.state ? 'primary' : 'secondary'"
- :disabled="isBotForceEnabled(bot) || isLoading[bot.id]"
+ :disabled="isBotLocked(bot) || isLoading[bot.id]"
@click="toggleBotState(bot)">
{{ toggleButtonTitle(bot) }}
</NcButton>
@@ -108,12 +108,12 @@ export default {
},
methods: {
- isBotForceEnabled(bot) {
- return bot.state === BOT.STATE.FORCE_ENABLED
+ isBotLocked(bot) {
+ return bot.state === BOT.STATE.NO_SETUP
},
async toggleBotState(bot) {
- if (this.isBotForceEnabled(bot)) {
+ if (this.isBotLocked(bot)) {
return
}
this.isLoading[bot.id] = true
@@ -122,7 +122,7 @@ export default {
},
toggleButtonTitle(bot) {
- if (this.isBotForceEnabled(bot)) {
+ if (this.isBotLocked(bot)) {
return t('spreed', 'Enabled')
}
diff --git a/src/constants.js b/src/constants.js
index 09b05f291..5681b8064 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -221,6 +221,6 @@ export const BOT = {
STATE: {
DISABLED: 0,
ENABLED: 1,
- FORCE_ENABLED: 2,
+ NO_SETUP: 2,
},
}
diff --git a/src/services/botsService.js b/src/services/botsService.js
index 0eb39018e..09c653256 100644
--- a/src/services/botsService.js
+++ b/src/services/botsService.js
@@ -24,6 +24,15 @@ import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
/**
+ * Get information about available bots for this instance
+ *
+ * @return {object} The axios response
+ */
+const getAllBots = async function() {
+ return axios.get(generateOcsUrl('/apps/spreed/api/v1/bot/admin'))
+}
+
+/**
* Get information about available bots for this conversation
*
* @param {string} token The conversation token
@@ -55,29 +64,9 @@ const disableBotForConversation = async function(token, id) {
return axios.delete(generateOcsUrl('/apps/spreed/api/v1/bot/{token}/{id}', { token, id }))
}
-/**
- * Send a message to bot in conversation
- *
- * @param {string} token The conversation token
- * @param {object} object Object with arguments
- * @param {string} object.message The message to send
- * @param {string} object.referenceId for the message to be able to later identify it again
- * @param {number} object.replyTo Parent id which this message is a reply to
- * @param {boolean} object.silent If sent silent the chat message will not create any notifications
- * @return {object} The axios response
- */
-const sendMessageToBot = async function(token, { message, referenceId, replyTo, silent }) {
- return axios.post(generateOcsUrl('/apps/spreed/api/v1/bot/{token}/message', { token }), {
- message,
- referenceId,
- replyTo,
- silent,
- })
-}
-
export {
+ getAllBots,
getConversationBots,
enableBotForConversation,
disableBotForConversation,
- sendMessageToBot,
}
diff --git a/src/views/AdminSettings.vue b/src/views/AdminSettings.vue
index bd65f6384..6991d79f0 100644
--- a/src/views/AdminSettings.vue
+++ b/src/views/AdminSettings.vue
@@ -26,6 +26,7 @@
<MatterbridgeIntegration />
<AllowedGroups />
<Commands />
+ <BotsSettings />
<WebServerSetupChecks />
<StunServers />
<TurnServers />
@@ -38,6 +39,7 @@
<script>
import AllowedGroups from '../components/AdminSettings/AllowedGroups.vue'
+import BotsSettings from '../components/AdminSettings/BotsSettings.vue'
import Commands from '../components/AdminSettings/Commands.vue'
import GeneralSettings from '../components/AdminSettings/GeneralSettings.vue'
import HostedSignalingServer from '../components/AdminSettings/HostedSignalingServer.vue'
@@ -54,6 +56,7 @@ export default {
components: {
AllowedGroups,
+ BotsSettings,
Commands,
GeneralSettings,
HostedSignalingServer,