multi-connections and basic settings

This commit is contained in:
Gabriel Pastori 2023-11-06 18:44:35 -03:00
parent 687d9a1402
commit 6a9e1c54d4
7 changed files with 363 additions and 26 deletions

View File

@ -21,6 +21,7 @@
</template> </template>
<script> <script>
import Options from "./settings/Options.vue";
import Webhook from "./settings/Webhook.vue"; import Webhook from "./settings/Webhook.vue";
import Websocket from "./settings/Websocket.vue"; import Websocket from "./settings/Websocket.vue";
import Rabbitmq from "./settings/Rabbitmq.vue"; import Rabbitmq from "./settings/Rabbitmq.vue";
@ -32,6 +33,7 @@ import MyChats from "./message/MyChats.vue";
import HasWhatsapp from "./message/HasWhatsapp.vue"; import HasWhatsapp from "./message/HasWhatsapp.vue";
export default { export default {
components: { components: {
Options,
Webhook, Webhook,
Websocket, Websocket,
Rabbitmq, Rabbitmq,
@ -48,7 +50,7 @@ export default {
id: "settings", id: "settings",
icon: "mdi-cog", icon: "mdi-cog",
title: "Configurações", title: "Configurações",
components: ["Webhook", "Websocket", "Rabbitmq", "Chatwoot", "Typebot"], components: ["Options","Webhook", "Websocket", "Rabbitmq", "Chatwoot", "Typebot"],
}, },
{ {
id: "message", id: "message",

View File

@ -0,0 +1,187 @@
<template>
<v-card variant="outlined" :loading="loading">
<v-card-title class="d-flex align-center">
<v-icon start>mdi-cellphone-cog</v-icon>
Comportamento
<v-spacer></v-spacer>
<v-btn
size="small"
icon
:disabled="loading"
variant="tonal"
@click="expanded = !expanded"
:style="{ transform: expanded ? 'rotate(180deg)' : '' }"
>
<v-icon>mdi-chevron-down</v-icon>
</v-btn>
</v-card-title>
<v-card-text v-if="expanded">
<v-alert v-if="error" type="error" class="mb-3">
{{ error }}
</v-alert>
<v-form v-model="valid">
<div class="d-flex align-center gap-4 flex-wrap">
<v-checkbox
class="flex-grow-0 flex-shrink-0"
v-model="optionsData.reject_call"
:disabled="loading"
label="Rejeitar chamadas"
hide-details
density="compact"
></v-checkbox>
<v-text-field
class="flex-grow-1 flex-shrink-0"
v-model="optionsData.msg_call"
:disabled="loading || !optionsData.reject_call"
label="Mensagem de rejeição"
hide-details
style="min-width: 200px"
></v-text-field>
</div>
<div class="d-flex gap-x-4 flex-wrap">
<v-checkbox
class="flex-grow-0"
v-model="optionsData.groups_ignore"
:disabled="loading"
label="Ignorar grupos"
hide-details
density="compact"
></v-checkbox>
<v-checkbox
class="flex-grow-0"
v-model="optionsData.always_online"
:disabled="loading"
label="Sempre online"
hide-details
density="compact"
></v-checkbox>
<v-checkbox
class="flex-grow-0"
v-model="optionsData.read_messages"
:disabled="loading"
label="Marcar mensagens como lidas"
hide-details
density="compact"
></v-checkbox>
<v-checkbox
class="flex-grow-0"
v-model="optionsData.read_status"
:disabled="loading"
label="Marcar status como visto"
hide-details
density="compact"
></v-checkbox>
</div>
</v-form>
</v-card-text>
<v-card-actions v-if="expanded">
<v-spacer></v-spacer>
<v-btn
:disabled="
!valid ||
JSON.stringify(optionsData) === JSON.stringify(defaultOptionsData)
"
:loading="loading"
color="primary"
@click="saveOptions"
variant="tonal"
>
Salvar
</v-btn>
</v-card-actions>
</v-card>
</template>
<script>
import instanceController from "@/services/instanceController";
const defaultOptions = () => ({
reject_call: false,
msg_call: "",
groups_ignore: false,
always_online: false,
read_messages: false,
read_status: false,
})
export default {
name: "InstanceOptions",
props: {
instance: {
type: Object,
required: true,
},
},
data: () => ({
expanded: false,
loading: false,
error: false,
valid: false,
optionsData: {
reject_call: false,
msg_call: "",
groups_ignore: false,
always_online: false,
read_messages: false,
read_status: false,
},
defaultOptionsData: {
reject_call: false,
msg_call: "",
groups_ignore: false,
always_online: false,
read_messages: false,
read_status: false,
},
}),
methods: {
async saveOptions() {
try {
this.loading = true;
this.error = false;
await instanceController.options.set(
this.instance.instance.instanceName,
this.optionsData
);
this.defaultOptionsData = Object.assign(defaultOptions(), this.optionsData);
} catch (e) {
this.error = e.message?.message || e.message || e;
} finally {
this.loading = false;
}
},
async loadOptions() {
try {
this.loading = true;
this.error = false;
const optionsData = await instanceController.options.get(
this.instance.instance.instanceName
);
this.optionsData = Object.assign(defaultOptions(), optionsData);
this.defaultOptionsData = Object.assign(defaultOptions(), optionsData);
} catch (e) {
this.error = e.message?.message || e.message || e;
} finally {
this.loading = false;
}
},
},
watch: {
expanded(val) {
if (val) this.loadOptions();
},
},
};
</script>
<style></style>

View File

@ -2,7 +2,6 @@
<v-dialog <v-dialog
v-model="dialog" v-model="dialog"
max-width="500px" max-width="500px"
:persistent="!AppStore.validConnection"
> >
<v-card> <v-card>
<v-card-text class="d-flex flex-column gap-4"> <v-card-text class="d-flex flex-column gap-4">
@ -48,7 +47,6 @@
<v-card-actions> <v-card-actions>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn <v-btn
v-if="AppStore.validConnection"
text text
@click="dialog = false" @click="dialog = false"
:disabled="loading" :disabled="loading"

View File

@ -1,5 +1,9 @@
<template> <template>
<v-dialog v-model="dialog" max-width="500px" :persistent="!AppStore.validConnection"> <v-dialog
v-model="dialog"
max-width="500px"
:persistent="!AppStore.validConnection"
>
<v-card> <v-card>
<v-card-text> <v-card-text>
<v-form v-model="valid"> <v-form v-model="valid">
@ -31,12 +35,27 @@
</v-alert> </v-alert>
</v-card-text> </v-card-text>
<v-card-actions> <v-card-actions>
<v-btn
v-if="!AppStore.connection.host === connection.host"
text
@click="dialog = false"
>
Cancel
</v-btn>
<v-spacer></v-spacer> <v-spacer></v-spacer>
<v-btn v-if="AppStore.validConnection" text @click="dialog = false" :disabled="loading">Cancel</v-btn> <v-btn
v-if="AppStore.validConnection"
text
@click="dialog = false"
:disabled="loading"
>
Cancel
</v-btn>
<v-btn <v-btn
color="success" color="success"
variant="tonal" variant="tonal"
@click="save" @click="save()"
:disabled="!valid" :disabled="!valid"
:loading="loading" :loading="loading"
> >
@ -44,6 +63,60 @@
</v-btn> </v-btn>
</v-card-actions> </v-card-actions>
</v-card> </v-card>
<v-card class="mt-2" v-if="connectionsList && connectionsList.length > 1">
<v-card-text>
<h3 class="mb-4">Conexões salvas</h3>
<v-list>
<v-list-item
v-for="conect in connectionsList"
:key="conect.host"
:disabled="
loading ||
(conect.host === AppStore.connection.host &&
AppStore.validConnection)
"
@click="save(conect)"
>
<v-list-item-content>
<v-list-item-title>{{
conect.host.replace(/https?:\/\//, "")
}}</v-list-item-title>
<!-- <v-list-item-subtitle>
{{ connection.globalApiKey.slice(0, 10) }}...
</v-list-item-subtitle> -->
</v-list-item-content>
<template v-slot:append>
<v-btn
@click.stop="removeConnection(conect)"
icon
v-if="
conect.host !== AppStore.connection.host ||
!AppStore.validConnection
"
size="x-small"
variant="tonal"
color="error"
:disabled="loading"
>
<v-icon>mdi-delete</v-icon>
</v-btn>
<v-btn
icon
v-else
size="x-small"
variant="tonal"
color="success"
:disabled="loading"
>
<v-icon>mdi-check</v-icon>
</v-btn>
</template>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-dialog> </v-dialog>
</template> </template>
@ -65,12 +138,15 @@ export default {
AppStore: useAppStore(), AppStore: useAppStore(),
}), }),
methods: { methods: {
async save() { removeConnection(connection) {
this.AppStore.removeConnection(connection);
},
async save(connection) {
try { try {
this.loading = true; this.loading = true;
this.error = false; this.error = false;
await this.AppStore.setConnection(this.connection); await this.AppStore.setConnection(connection || this.connection);
this.dialog = false; this.dialog = false;
} catch (e) { } catch (e) {
this.error = e.message?.message || e.message || e; this.error = e.message?.message || e.message || e;
@ -80,10 +156,15 @@ export default {
}, },
open() { open() {
this.dialog = true; this.dialog = true;
this.connection = this.AppStore.connection; this.connection = Object.assign({}, this.AppStore.connection);
}, },
}, },
computed: {
connectionsList() {
return this.AppStore.connectionsList;
},
},
emits: ["close"], emits: ["close"],
}; };
</script> </script>

View File

@ -1,6 +1,32 @@
import http from "../http-common"; import http from "../http-common";
const findOptions = async (instanceName) => {
return await http
.get("/settings/find/:instance", {
params: {
instance: instanceName
}
})
.then((r) => r.data)
.catch((error) => {
throw error.response?.data || error.response || error;
});
}
const setOptions = async (instanceName, data) => {
return await http
.post("/settings/set/:instance", data, {
params: {
instance: instanceName
}
})
.then((r) => r.data)
.catch((error) => {
throw error.response?.data || error.response || error;
});
}
const findWebhook = async (instanceName) => { const findWebhook = async (instanceName) => {
return await http return await http
.get("/webhook/find/:instance", { .get("/webhook/find/:instance", {
@ -115,7 +141,14 @@ const setTypebot = async (instanceName, data) => {
}); });
} }
export default { export default {
options: {
get: findOptions,
set: setOptions,
},
webhook: { webhook: {
get: findWebhook, get: findWebhook,
set: setWebhook, set: setWebhook,

View File

@ -23,6 +23,9 @@ export const useAppStore = defineStore('app', {
}, },
instancesKeys: {}, instancesKeys: {},
instancesList: [], instancesList: [],
// lista de "contatos" de conexoes
connectionsList: [],
}), }),
actions: { actions: {
@ -51,16 +54,16 @@ export const useAppStore = defineStore('app', {
async loadInstance(instanceName) { async loadInstance(instanceName) {
try { try {
const { host, globalApiKey } = this.connection; const { host, globalApiKey } = this.connection;
return this.reconnect()
const response = await axios({ // const response = await axios({
method: 'GET', // method: 'GET',
baseURL: host, // baseURL: host,
headers: { // headers: {
'Content-Type': 'application/json', // 'Content-Type': 'application/json',
'apikey': globalApiKey // 'apikey': globalApiKey
}, // },
url: `/instance/fetchInstances?instanceName=${instanceName}` // url: `/instance/fetchInstances?instanceName=${instanceName}`
}) // })
} catch (e) { } catch (e) {
this.connection.valid = false this.connection.valid = false
@ -71,6 +74,9 @@ export const useAppStore = defineStore('app', {
async reconnect() { async reconnect() {
try { try {
const { host, globalApiKey } = this.connection const { host, globalApiKey } = this.connection
if (!host || !globalApiKey) {
throw new Error('Invalid connection')
}
const response = await axios({ const response = await axios({
method: 'GET', method: 'GET',
baseURL: host, baseURL: host,
@ -101,28 +107,54 @@ export const useAppStore = defineStore('app', {
this.instancesKeys[instance] = key this.instancesKeys[instance] = key
}, },
removeConnection({ host }) {
const currentKey = this.connectionsList.findIndex(
(item) => item.host === host
)
if (currentKey !== -1)
this.connectionsList.splice(currentKey, 1)
this.saveLocalStorage()
},
saveConnection({ host, globalApiKey }) { saveConnection({ host, globalApiKey }) {
this.connection = { this.connection = {
valid: true, valid: true,
host, host,
globalApiKey, globalApiKey,
} }
const currentKey = this.connectionsList.findIndex(
(item) => item.host === host
)
if (currentKey === -1) {
this.connectionsList.push({ host, globalApiKey })
} else {
this.connectionsList[currentKey] = { host, globalApiKey }
}
this.saveLocalStorage()
},
saveLocalStorage() {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
window.localStorage.setItem('connection', JSON.stringify({ window.localStorage.setItem('connection', JSON.stringify(this.connection))
host, window.localStorage.setItem('connectionsList', JSON.stringify(this.connectionsList))
globalApiKey,
}))
} }
}, },
async loadConnection() { async loadConnection() {
if (typeof window !== 'undefined') { if (typeof window !== 'undefined') {
const connectionsList = window.localStorage.getItem('connectionsList')
if (connectionsList) {
this.connectionsList = JSON.parse(connectionsList || '[]')
}
const connection = window.localStorage.getItem('connection') const connection = window.localStorage.getItem('connection')
if (connection) { if (connection) {
this.connection = JSON.parse(connection) this.connection = JSON.parse(connection || '{}')
return this.reconnect() return this.reconnect()
} }
} }
} },
} }
}) })

View File

@ -39,7 +39,11 @@ export default {
} }
}, },
}, },
watch: {}, watch: {
instance(val, oldVal) {
if (!val && oldVal) this.$router.push("/");
},
},
computed: { computed: {
instance() { instance() {