diff options
author | Maksim Sukharev <antreesy.web@gmail.com> | 2023-08-10 12:08:17 +0200 |
---|---|---|
committer | Joas Schilling <coding@schilljs.com> | 2023-08-10 16:26:12 +0200 |
commit | 6169672f469c74ec254aa0f8313e33c974fa45f6 (patch) | |
tree | b9be7d2a7fb8e0b19d7cd93e745146661c639d8b | |
parent | 5e10ea4dce0a9df9a474b661716004fe3ea68f19 (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.vue | 197 | ||||
-rw-r--r-- | src/components/ConversationSettings/BotsSettings.vue | 10 | ||||
-rw-r--r-- | src/constants.js | 2 | ||||
-rw-r--r-- | src/services/botsService.js | 31 | ||||
-rw-r--r-- | src/views/AdminSettings.vue | 3 |
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, |