├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── Dockerfile ├── LICENSE.md ├── README.md ├── README.pt_BR.md ├── bin └── evolution-manager ├── docker-compose.yml ├── docs ├── en │ ├── cli.md │ ├── docker.md │ ├── general │ │ └── node-install.md │ └── index.md └── pt_br │ ├── cli.md │ ├── docker.md │ ├── general │ └── node-install.md │ └── index.md ├── index.html ├── jsconfig.json ├── lib ├── api │ ├── changeVersion.js │ ├── index.js │ ├── migrateToMongo │ │ ├── index.js │ │ └── migrators │ │ │ ├── chats.js │ │ │ ├── contacts.js │ │ │ ├── instance.js │ │ │ ├── messageUpdate.js │ │ │ └── newMessage.js │ ├── setup.js │ ├── uninstall.js │ └── view.router.ts.patch ├── cli.js ├── help.js ├── pm2 │ ├── delete.js │ ├── index.js │ ├── reset.js │ ├── setup.js │ ├── start.js │ └── stop.js ├── postinstall.js ├── server.js └── utils │ ├── build.js │ ├── detectPm2ProcessId.js │ ├── revertToVersion.js │ ├── verbose.js │ ├── verifyEvolutionInstallation.js │ └── verifyPm2Installation.js ├── package-lock.json ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── assets │ ├── chatwoot │ │ ├── chatwoot_api.png │ │ ├── chatwoot_api_1.png │ │ ├── chatwoot_api_2.png │ │ └── chatwoot_api_3.png │ ├── logo.png │ └── pix.svg ├── components │ ├── HelloWorld.vue │ ├── global │ │ ├── EventsSelect.vue │ │ └── HelpTooltip.vue │ ├── instance │ │ ├── InstanceBody.vue │ │ ├── InstanceHeader.vue │ │ ├── message │ │ │ ├── HasWhatsapp.vue │ │ │ ├── MyChats.vue │ │ │ ├── MyContacts.vue │ │ │ ├── MyGroups.vue │ │ │ └── OpenSendMessage.vue │ │ ├── profile │ │ │ ├── BasicInfo.vue │ │ │ ├── ConnectionAlert.vue │ │ │ ├── Privacy.vue │ │ │ └── ProfilePhoto.vue │ │ └── settings │ │ │ ├── Chatwoot.vue │ │ │ ├── Options.vue │ │ │ ├── Rabbitmq.vue │ │ │ ├── Typebot.vue │ │ │ ├── Webhook.vue │ │ │ └── Websocket.vue │ └── modal │ │ ├── About.vue │ │ ├── ChatwootConfig.vue │ │ ├── ConnectPhone.vue │ │ ├── Contribute.vue │ │ ├── CreateInstance.vue │ │ ├── GroupAddParticipantModal.vue │ │ ├── GroupModal.vue │ │ ├── InstanceApiKey.vue │ │ ├── SendMessage.vue │ │ ├── Settings.vue │ │ ├── ShareConnection.vue │ │ └── TypebotSessions.vue ├── helpers │ ├── copyToClipboard.js │ ├── deepMerge.js │ └── mappers │ │ ├── status.js │ │ └── typebotStatus.js ├── http-common.js ├── i18n │ ├── en.js │ ├── es.js │ └── pt.js ├── layouts │ ├── default │ │ ├── AppBar.vue │ │ ├── AppFooter.vue │ │ ├── Default.vue │ │ └── View.vue │ └── doc │ │ ├── AppBar.vue │ │ ├── AppFooter.vue │ │ ├── Index.vue │ │ └── View.vue ├── main.js ├── plugins │ ├── index.js │ └── vuetify.js ├── router │ └── index.js ├── services │ ├── instanceChatController.js │ ├── instanceController.js │ ├── instanceGroupController.js │ ├── instanceProfileController.js │ └── instanceSettingsController.js ├── store │ ├── app.js │ ├── doc.js │ └── index.js ├── styles │ └── settings.scss └── views │ ├── Doc.vue │ ├── Home.vue │ └── Instance.vue ├── vercel.json └── vite.config.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | not ie 11 5 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: [ 7 | 'plugin:vue/vue3-essential', 8 | 'eslint:recommended', 9 | ], 10 | } 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | # local env files 6 | .env.local 7 | .env.*.local 8 | 9 | # Log files 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | pnpm-debug.log* 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | .vercel 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use a imagem oficial do Node.js 20 como base 2 | FROM node:20-slim 3 | 4 | WORKDIR /usr/src/app 5 | 6 | RUN npm install -g vite 7 | 8 | RUN ln -s /usr/local/bin/node /usr/bin/node 9 | 10 | ENTRYPOINT ["npx", "evolution-manager", "server", "start"] 11 | 12 | EXPOSE 9615 13 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Gabriel Pastori 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Evolution Manager 2 | 3 | ## Introduction 4 | 5 | Evolution Manager is an open-source management tool for the Evolution API, designed to streamline the administration and monitoring of instances. It can be accessed online at [Evolution Manager](https://github.com/gabrielpastori1/evolution-manager). 6 | 7 | --- 8 | 9 | 🇧🇷 **Atenção, Comunidade Brasileira!** 🇧🇷 10 | 11 | Se você é um desenvolvedor ou usuário brasileiro interessado no Evolution Manager, temos boas notícias! Agora você pode acessar a documentação completa do projeto em português. Isso facilitará seu entendimento e uso desta ferramenta incrível. Clique no link abaixo para ler o README em português: 12 | 13 | 🔗 [Leia o README em Português](https://github.com/gabrielpastori1/evolution-manager/blob/main/README.pt_BR.md) 14 | 15 | --- 16 | 17 | ## Features 18 | 19 | - **Instance Management**: Create, manage, and delete instances. 20 | - **Instance Settings**: Customize behavior settings (e.g., disabling calls, always-online mode), webhook integration, RabbitMQ, WebSocket, Chatwoot, and Typebot configurations. 21 | - **User Utilities**: Check user numbers, search for conversations, and find groups. 22 | 23 | ## Limitations 24 | 25 | - The version hosted on Vercel requires the server to have an SSL certificate. 26 | 27 | ## Technology 28 | 29 | - The project is built using Vue.js v3 and Vuetify. 30 | 31 | ## Evolution-Manager CLI - Documentation 32 | 33 | For detailed information on how to use the Evolution-Manager CLI, please refer to the documentation available at the following links: 34 | 35 | 🔗 Full Documentation: [Documentation in English](https://github.com/gabrielpastori1/evolution-manager/blob/main/docs/en/cli.md) 36 | 37 | ## Docker Image - Documentation 38 | 39 | For detailed information on using the Docker image, including configurations and examples, please refer to our comprehensive documentation. You will find step-by-step instructions, as well as helpful tips to make the most of the Evolution Manager's Docker image. 40 | 41 | 🔗 Full Documentation: [Documentation in English](https://github.com/gabrielpastori1/evolution-manager/tree/main/docs/en/docker.md) 42 | 43 | ## Self-Hosted - Evolution Manager CLI and PM2 44 | 45 | ### Straight to the Point: Quick Setup with PM2 46 | 47 | To quickly install Evolution Manager globally and set it up with PM2, follow these commands: 48 | 49 | 1. **Install Evolution Manager Globally**: 50 | 51 | ```bash 52 | npm install -g evolution-manager 53 | ``` 54 | 55 | 2. **Set Up PM2 for Evolution Manager**: 56 | 57 | ```bash 58 | evolution-manager pm2 setup 59 | ``` 60 | 61 | These two steps will install the Evolution Manager CLI globally on your system and configure it to run with PM2, a powerful process manager. 62 | 63 | ### Installation and Configuration 64 | 65 | These two steps will install the Evolution Manager CLI globally on your system and configure it to run with PM2, a powerful process manager. 66 | 67 | 1. **Install Evolution Manager Globally**: 68 | - Ensure Node.js and NPM are installed on your system. 69 | - Install Evolution Manager globally using NPM to access the CLI (Command Line Interface): 70 | 71 | ```bash 72 | npm install -g evolution-manager 73 | ``` 74 | 75 | 2. **Using the CLI**: 76 | - After installation, access the CLI commands by typing `evolution-manager` in your terminal. 77 | - Available commands include: 78 | - `help`: Displays a list of available commands and their descriptions. 79 | - `server`: Server-related operations. 80 | - `start [--port=9615]`: Starts the server on the specified port (default: 9615). 81 | - `build`: Builds the project. 82 | - `pm2`: Manages the process with PM2. 83 | - `setup`: Sets up PM2 for the project. 84 | - `start`: Starts the service with PM2. 85 | - `stop`: Stops the service in PM2. 86 | - `restart`: Restarts the service in PM2. 87 | - `delete`: Removes the service from PM2. 88 | 89 | 3. **Running the Project with PM2**: 90 | - To set up and manage the service with PM2, start with the setup command: 91 | 92 | ```bash 93 | evolution-manager pm2 setup 94 | ``` 95 | 96 | - Then, you can start, stop, restart, or delete the service using the respective `pm2` commands in the CLI. 97 | 98 | These instructions provide a streamlined method for managing Evolution Manager across various systems, utilizing PM2 for efficient service start-up, maintenance, and control. 99 | 100 | ## Development Setup 101 | 102 | 1. **Prerequisites**: Ensure you have `yarn` installed on your system. 103 | 2. **Clone the Repository**: 104 | 105 | ```bash 106 | git clone https://github.com/gabrielpastori1/evolution-manager.git 107 | cd evolution-manager 108 | ``` 109 | 110 | 3. **Install Dependencies**: 111 | 112 | ```bash 113 | yarn install 114 | ``` 115 | 116 | 4. **Run Development Server**: 117 | 118 | ```bash 119 | yarn dev 120 | ``` 121 | 122 | This will start a local development server. You can access the app at `localhost:8080`. 123 | 124 | ## Building the Project 125 | 126 | To build the project for production, run: 127 | 128 | ```bash 129 | yarn build 130 | ``` 131 | 132 | This will create a `dist` folder with the compiled assets. 133 | 134 | ## Contributing 135 | 136 | Contributions are an essential part of the Evolution Manager project. Whether you're contributing code, suggestions, or feedback, your input is invaluable. To facilitate contributions, we have included a direct means for donations: 137 | 138 | ### Making a Donation 139 | 140 | If you wish to support the project financially, we have provided a QR code for Pix donations. Your generosity helps in maintaining and evolving this open-source tool. 141 | 142 | Pix Donation QR Code 143 | 144 | ### Contributing Code or Ideas 145 | 146 | We also welcome code contributions and innovative ideas. If you're interested in contributing in this way, please read our contributing guidelines for more information on how to get started. 147 | 148 | Your support, in any form, makes a significant difference and is greatly appreciated. Thank you for being a part of the Evolution Manager community! 149 | 150 | ## License 151 | 152 | This project is open-source and available under the [MIT License](LICENSE.md). 153 | -------------------------------------------------------------------------------- /README.pt_BR.md: -------------------------------------------------------------------------------- 1 | # Evolution Manager 2 | 3 | ## Introdução 4 | 5 | O Evolution Manager é uma ferramenta de gerenciamento open-source para a Evolution API, projetada para facilitar a administração e monitoramento de instâncias. Pode ser acessada online em [Evolution Manager](https://github.com/gabrielpastori1/evolution-manager). 6 | 7 | ## Funcionalidades 8 | 9 | - **Gerenciamento de Instâncias**: Criação, gerenciamento e exclusão de instâncias. 10 | - **Configurações de Instância**: Personalização das configurações de comportamento (por exemplo, desativar chamadas, modo sempre online), integração com webhook, RabbitMQ, WebSocket, Chatwoot e configurações do Typebot. 11 | - **Utilitários para Usuários**: Verificação de números de usuários, busca por conversas e grupos. 12 | 13 | ## Limitações 14 | 15 | - A versão hospedada na Vercel requer que o servidor tenha um certificado SSL. 16 | 17 | ## Tecnologia 18 | 19 | - O projeto é desenvolvido usando Vue.js v3 e Vuetify. 20 | 21 | ## Evolution-Manager CLI - Documentação 22 | 23 | Para informações detalhadas sobre como usar o Evolution-Manager CLI, consulte a documentação disponível nos seguintes links: 24 | 25 | 🔗 Documentação completa: [Documentação em Português](https://github.com/gabrielpastori1/evolution-manager/blob/main/docs/pt_br/cli.md) 26 | 27 | ## Imagem Docker - Documentação 28 | 29 | Para obter informações detalhadas sobre como usar a imagem Docker, incluindo configurações e exemplos, acesse a nossa documentação completa. Você encontrará instruções passo a passo, bem como dicas úteis para maximizar o uso da imagem Docker do Evolution Manager. 30 | 31 | 🔗 Documentação completa: [Documentação em Português](https://github.com/gabrielpastori1/evolution-manager/tree/main/docs/pt_br/docker.md) 32 | 33 | --- 34 | 35 | ## Auto-Hospedagem - CLI e PM2 do Evolution Manager 36 | 37 | ### Direto ao Ponto: Configuração Rápida com PM2 38 | 39 | Para instalar rapidamente o Evolution Manager globalmente e configurá-lo com o PM2, siga estes comandos: 40 | 41 | 1. **Instalar o Evolution Manager Globalmente**: 42 | 43 | ```bash 44 | npm install -g evolution-manager 45 | ``` 46 | 47 | 2. **Configurar PM2 para o Evolution Manager**: 48 | 49 | ```bash 50 | evolution-manager pm2 setup 51 | ``` 52 | 53 | Estes dois passos instalarão o CLI do Evolution Manager globalmente em seu sistema e o configurarão para funcionar com o PM2, um gerenciador de processos poderoso. 54 | 55 | ### Instalação e Configuração 56 | 57 | Esses dois passos instalarão o CLI do Evolution Manager globalmente em seu sistema e o configurarão para funcionar com o PM2, um gerenciador de processos poderoso. 58 | 59 | 1. **Instalar o Evolution Manager Globalmente**: 60 | - Certifique-se de ter o Node.js e o NPM instalados em seu sistema. 61 | - Instale o Evolution Manager globalmente usando o NPM para acessar o CLI (Interface de Linha de Comando): 62 | 63 | ```bash 64 | npm install -g evolution-manager 65 | ``` 66 | 67 | 2. **Usando o CLI**: 68 | - Após a instalação, acesse os comandos do CLI digitando `evolution-manager` em seu terminal. 69 | - Os comandos disponíveis incluem: 70 | - `help`: Exibe uma lista de comandos disponíveis e suas descrições. 71 | - `server`: Operações relacionadas ao servidor. 72 | - `start [--port=9615]`: Inicia o servidor na porta especificada (padrão: 9615). 73 | - `build`: Constrói o projeto. 74 | - `pm2`: Gerencia o processo com o PM2. 75 | - `setup`: Configura o PM2 para o projeto. 76 | - `start`: Inicia o serviço com o PM2. 77 | - `stop`: Para o serviço no PM2. 78 | - `restart`: Reinicia o serviço no PM2. 79 | - `delete`: Remove o serviço do PM2. 80 | 81 | 3. **Executando o Projeto com o PM2**: 82 | - Para configurar e gerenciar o serviço com o PM2, comece com o comando de configuração: 83 | 84 | ```bash 85 | evolution-manager pm2 setup 86 | ``` 87 | 88 | - Em seguida, você pode iniciar, parar, reiniciar ou excluir o serviço usando os respectivos comandos `pm2` no CLI. 89 | 90 | Estas instruções fornecem um método simplificado para gerenciar o Evolution Manager em vários sistemas, utilizando o PM2 para um eficiente início de serviço 91 | 92 | ## Configuração para Desenvolvimento 93 | 94 | 1. **Pré-requisitos**: Certifique-se de ter o `yarn` instalado no seu sistema. 95 | 2. **Clonar o Repositório**: 96 | 97 | ```bash 98 | git clone https://github.com/gabrielpastori1/evolution-manager.git 99 | cd evolution-manager 100 | ``` 101 | 102 | 3. **Instalar Dependências**: 103 | 104 | ```bash 105 | yarn install 106 | ``` 107 | 108 | 4. **Executar o Servidor de Desenvolvimento**: 109 | 110 | ```bash 111 | yarn dev 112 | ``` 113 | 114 | Isso iniciará um servidor de desenvolvimento local. Você pode acessar o aplicativo em `localhost:8080`. 115 | 116 | ## Construção do Projeto 117 | 118 | Para construir o projeto para produção, execute: 119 | 120 | ```bash 121 | yarn build 122 | ``` 123 | 124 | Isso criará uma pasta `dist` com os ativos compilados. 125 | 126 | ## Contribuindo 127 | 128 | As contribuições são uma parte essencial do projeto Evolution Manager. Seja contribuindo com código, sugestões ou feedback, sua participação é inestimável. Para facilitar as contribuições, incluímos um meio direto para doações: 129 | 130 | ### Fazendo uma Doação 131 | 132 | Se desejar apoiar o projeto financeiramente, disponibilizamos um QR code para doações via Pix. Sua generosidade ajuda na manutenção e evolução desta ferramenta de código aberto. 133 | 134 | QR Code para Doação Pix 135 | 136 | ### Contribuindo com Código ou Ideias 137 | 138 | Também recebemos contribuições de código e ideias inovadoras. Se você tem interesse em contribuir dessa forma, por favor, leia nossas diretrizes de contribuição para mais informações sobre como começar. 139 | 140 | Seu apoio, de qualquer forma, faz uma grande diferença e é muito apreciado. Obrigado por fazer parte da comunidade Evolution Manager! 141 | 142 | ## Licença 143 | 144 | Este projeto é de código aberto e está disponível sob a [Licença MIT](LICENSE.md). 145 | -------------------------------------------------------------------------------- /bin/evolution-manager: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | require('./../lib/cli.js'); -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | # Use this compose with traefik proxy manager 2 | version: '3' 3 | services: 4 | evolution-manager: 5 | image: "gabrielpastori1/evolution-manager:latest" 6 | ports: 7 | - "9615:9615" 8 | labels: 9 | - traefik.enable=true 10 | - traefik.http.routers.evolution-manager.service=evolution-manager 11 | - traefik.http.services.evolution-manager.loadbalancer.server.port=9615 12 | - traefik.http.routers.evolution-manager.rule=Host(`manager.yourdomain.com`) #Replace this with the subdomain that you wishes, dont forget to point the domain to your VPS ip address 13 | - traefik.http.routers.evolution-manager.entrypoints=https # Some people name the entrypoint as "websecure" look at your original traefik compose file to find the correct entrypoint name 14 | - traefik.http.routers.evolution-manager.tls.certresolver=letsencrypt # Some people name the certResolver as "le" look at your original traefik compose file to find the correct certResolver name 15 | networks: 16 | - traefik_public_example_network 17 | networks: 18 | traefik_public_example_network: 19 | external: true 20 | -------------------------------------------------------------------------------- /docs/en/cli.md: -------------------------------------------------------------------------------- 1 | [title]: \\ "CLI" 2 | 3 | # Evolution-Manager CLI 4 | 5 | ## Description 6 | The Evolution-Manager CLI is a command-line tool designed to manage servers, PM2 processes, and interact with the "evolution-api" project. 7 | 8 | ## Installation 9 | To install the Evolution-Manager CLI, run the following command: 10 | ``` 11 | npm install -g evolution-manager 12 | ``` 13 | 14 | ## Available Commands 15 | 16 | ### General 17 | - `help`: Displays a list of available commands. Refer to this document for additional details on each command. 18 | 19 | ### Server 20 | - `server start [--port=9615]`: Starts a temporary server in the terminal, ideal for local use. The `--port` parameter allows specifying the port, with `9615` as the default. 21 | - `server build`: Executes the server build but does not start it. (Currently without specific use). 22 | 23 | ### PM2 24 | Interacts with PM2 to manage Evolution Manager processes: 25 | - `pm2 setup`: Configures PM2 to host the Evolution Manager. Automatically installs PM2 if not present. 26 | - `pm2 start`: Starts the Evolution Manager process in PM2. 27 | - `pm2 stop`: Stops the Evolution Manager process in PM2. 28 | - `pm2 restart`: Restarts the Evolution Manager process in PM2. 29 | - `pm2 delete`: Removes the Evolution Manager process from PM2. 30 | 31 | ### API 32 | 33 | The API section of the Evolution-Manager CLI includes various functions for managing the installation and versions of the Evolution Manager within the API. The available commands are: 34 | 35 | - `setup` or `install`: Installs the manager inside the Evolution API at the path `/manager`. This command can also be accessed using the shorthand `i`. 36 | - `uninstall`: Uninstalls the manager from the Evolution API. 37 | - `changeVersion` or `cv`: Switches to a specific version of the Evolution API, whether newer or older. Example usage: `changeVersion --v=1.5.0`. 38 | 39 | These commands provide a flexible and powerful command-line interface for managing the versions and configuration of the manager in your Evolution API installation. 40 | 41 | ## Typical Usage Flow 42 | 1. Install the CLI globally. 43 | 2. Use `help` to view available commands. 44 | 3. Use PM2 commands to host the Evolution Manager. 45 | 4. Run `server start` for a local temporary server. 46 | 5. Within the "evolution-api" installation, use `api setup` to update to the new manager. 47 | -------------------------------------------------------------------------------- /docs/en/docker.md: -------------------------------------------------------------------------------- 1 | # Docker Image of Evolution Manager 2 | 3 | This README file describes how to use the Evolution Manager Docker image and set up a domain using [Traefik](#configuring-the-domain-with-traefik) or [NGINX](#configuring-the-domain-with-nginx). 4 | 5 | ## Using the Docker Image 6 | 7 | The Evolution Manager Docker image provides an easy and automated setup and updating of the system. When the container is started, the latest version of the Evolution Manager will be downloaded and installed. 8 | 9 | ### Prerequisites 10 | 11 | - Docker installed on your machine. 12 | - Basic knowledge of Docker operations. 13 | 14 | ### Running the Container 15 | 16 | To start a container with the Evolution Manager, execute the following command: 17 | 18 | ```sh 19 | docker run -d -p 9615:9615 gabrielpastori1/evolution-manager:latest 20 | ``` 21 | 22 | This command runs the container in detached mode and maps port 9615 of the container to port 9615 of the host. 23 | 24 | ### Exposed Port 25 | 26 | The image exposes port `9615`, which should be mapped to the corresponding port on the host. 27 | 28 | ## Configuring the Domain with Traefik 29 | 30 | To configure a domain and make the Evolution Manager accessible via the web, you can use Traefik as a reverse proxy. 31 | 32 | ### Prerequisites 33 | 34 | - Traefik configured on your server. 35 | - A domain pointing to the server where Traefik is running. 36 | 37 | ### Traefik Configuration 38 | 39 | 1. **Create a `docker-compose.yml` file** in the directory where you want to start the Evolution Manager, with the following content: 40 | 41 | ```yaml 42 | version: '3' 43 | 44 | services: 45 | evolution-manager: 46 | image: gabrielpastori1/evolution-manager:latest 47 | restart: unless-stopped 48 | ports: 49 | - "9615:9615" 50 | labels: 51 | - "traefik.enable=true" 52 | - "traefik.http.routers.evolution-manager.rule=Host(`your-domain.com`)" 53 | - "traefik.http.routers.evolution-manager.entrypoints=web" 54 | # Add other label configurations as necessary for Traefik 55 | 56 | networks: 57 | default: 58 | external: 59 | name: traefik_default 60 | ``` 61 | 62 | 2. **Replace** `your-domain.com` with the domain you want to use. 63 | 64 | 3. **Ensure** that the specified external network (`traefik_default`) matches the network used by Traefik in its setup. 65 | 66 | ### Starting the Service 67 | 68 | With the `docker-compose.yml` file configured, start the service with the following command: 69 | 70 | ```sh 71 | docker-compose up -d 72 | ``` 73 | 74 | Traefik will automatically detect the service and apply the rules defined in the container's labels. 75 | 76 | ## Configuring the Domain with NGINX 77 | 78 | If you prefer using NGINX as a reverse proxy instead of Traefik, follow the steps below. 79 | 80 | ### Prerequisites 81 | 82 | - NGINX installed on your server. 83 | - A domain pointing to your server's IP where NGINX is running. 84 | 85 | ### NGINX Configuration 86 | 87 | 1. **Create an NGINX Configuration File**: To redirect requests from your domain to the container, you need to create a configuration file in `/etc/nginx/conf.d/` with the following content: 88 | 89 | ```nginx 90 | server { 91 | listen 80; 92 | server_name your-domain.com; 93 | 94 | location / { 95 | proxy_pass http://localhost:9615; 96 | proxy_http_version 1.1; 97 | proxy_set_header Upgrade $http_upgrade; 98 | proxy_set_header Connection 'upgrade'; 99 | proxy_set_header Host $host; 100 | proxy_cache_bypass $http_upgrade; 101 | } 102 | } 103 | ``` 104 | 105 | 2. **Replace** `your-domain.com` with your actual domain. 106 | 107 | 3. **Check the NGINX Configuration**: Run `nginx -t` to ensure there are no errors in the configuration. 108 | 109 | 4. **Reload NGINX**: After verifying the configuration, reload the NGINX service with `service nginx reload` or `systemctl reload nginx`. 110 | 111 | Now NGINX will redirect requests from your domain to port `9615`, where your Docker container is listening. 112 | 113 | ## Support and Contributions 114 | 115 | For support, questions, or contributions, open an issue or send a pull request on the [GitHub repository](https://github.com/gabrielpastori1/evolution-manager). Your participation is very welcome! -------------------------------------------------------------------------------- /docs/en/general/node-install.md: -------------------------------------------------------------------------------- 1 | [title]: \\ "Installing Node Using NVM" 2 | 3 | # Installing Node.js with NVM 4 | 5 | This guide provides step-by-step instructions on how to install Node.js on Linux using NVM (Node Version Manager). 6 | 7 | ## Prerequisites 8 | 9 | - Access to a terminal in Linux. 10 | - Permissions to execute installation commands (usually as a root user or with `sudo`). 11 | 12 | ## Step 1: Install NVM 13 | 14 | NVM is a tool that allows you to manage multiple versions of Node.js. To install it, execute the following command in your terminal: 15 | 16 | ```bash 17 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash 18 | ``` 19 | 20 | *Note: You can check the latest version of NVM on their [GitHub page](https://github.com/nvm-sh/nvm).* 21 | 22 | After installation, close and reopen the terminal, and then run the following command to check if NVM was installed correctly: 23 | 24 | ```bash 25 | nvm --version 26 | ``` 27 | 28 | ## Step 2: Install Node.js 29 | 30 | With NVM installed, you can now install Node.js. To install the latest version, use the command: 31 | 32 | ```bash 33 | nvm install node 34 | ``` 35 | 36 | To install a specific version of Node.js, you can do: 37 | 38 | ```bash 39 | nvm install 18 40 | ``` 41 | 42 | After installation, verify the Node.js version with: 43 | 44 | ```bash 45 | node -v 46 | ``` 47 | 48 | ## Step 3: Use a Specific Version of Node.js 49 | 50 | You can switch between installed versions of Node.js with the `nvm use` command: 51 | 52 | ```bash 53 | nvm use 18 # replace 18 with the version you want to use 54 | ``` 55 | 56 | ## Conclusion 57 | 58 | You now have NVM installed on your Linux system, allowing you to install and manage multiple versions of Node.js. This is particularly useful for developers working on multiple projects that may require different versions of Node.js. 59 | -------------------------------------------------------------------------------- /docs/en/index.md: -------------------------------------------------------------------------------- 1 | [title]: \\ "About" 2 | 3 | # Evolution Manager 4 | 5 | ## Introduction 6 | 7 | Evolution Manager is an open-source management tool for the Evolution API, designed to streamline the administration and monitoring of instances. It can be accessed online at [Evolution Manager](https://github.com/gabrielpastori1/evolution-manager). 8 | 9 | --- 10 | 11 | 🇧🇷 **Atenção, Comunidade Brasileira!** 🇧🇷 12 | 13 | Se você é um desenvolvedor ou usuário brasileiro interessado no Evolution Manager, temos boas notícias! Agora você pode acessar a documentação completa do projeto em português. Isso facilitará seu entendimento e uso desta ferramenta incrível. Clique no link abaixo para ler o README em português: 14 | 15 | 🔗 [Leia o README em Português](https://github.com/gabrielpastori1/evolution-manager/blob/main/README.pt_BR.md) 16 | 17 | --- 18 | 19 | ## Features 20 | 21 | - **Instance Management**: Create, manage, and delete instances. 22 | - **Instance Settings**: Customize behavior settings (e.g., disabling calls, always-online mode), webhook integration, RabbitMQ, WebSocket, Chatwoot, and Typebot configurations. 23 | - **User Utilities**: Check user numbers, search for conversations, and find groups. 24 | 25 | ## Limitations 26 | 27 | - The version hosted on Vercel requires the server to have an SSL certificate. 28 | 29 | ## Technology 30 | 31 | - The project is built using Vue.js v3 and Vuetify. 32 | 33 | ## Evolution-Manager CLI - Documentation 34 | 35 | For detailed information on how to use the Evolution-Manager CLI, please refer to the documentation available at the following links: 36 | 37 | 🔗 Full Documentation: [Documentation in English](https://github.com/gabrielpastori1/evolution-manager/blob/main/docs/en/cli.md) 38 | 39 | ## Docker Image - Documentation 40 | 41 | For detailed information on using the Docker image, including configurations and examples, please refer to our comprehensive documentation. You will find step-by-step instructions, as well as helpful tips to make the most of the Evolution Manager's Docker image. 42 | 43 | 🔗 Full Documentation: [Documentation in English](https://github.com/gabrielpastori1/evolution-manager/tree/main/docs/en/docker.md) 44 | 45 | ## Self-Hosted - Evolution Manager CLI and PM2 46 | 47 | ### Straight to the Point: Quick Setup with PM2 48 | 49 | To quickly install Evolution Manager globally and set it up with PM2, follow these commands: 50 | 51 | 1. **Install Evolution Manager Globally**: 52 | 53 | ```bash 54 | npm install -g evolution-manager 55 | ``` 56 | 57 | 2. **Set Up PM2 for Evolution Manager**: 58 | 59 | ```bash 60 | evolution-manager pm2 setup 61 | ``` 62 | 63 | These two steps will install the Evolution Manager CLI globally on your system and configure it to run with PM2, a powerful process manager. 64 | 65 | ### Installation and Configuration 66 | 67 | These two steps will install the Evolution Manager CLI globally on your system and configure it to run with PM2, a powerful process manager. 68 | 69 | 1. **Install Evolution Manager Globally**: 70 | - Ensure Node.js and NPM are installed on your system. 71 | - Install Evolution Manager globally using NPM to access the CLI (Command Line Interface): 72 | 73 | ```bash 74 | npm install -g evolution-manager 75 | ``` 76 | 77 | 2. **Using the CLI**: 78 | - After installation, access the CLI commands by typing `evolution-manager` in your terminal. 79 | - Available commands include: 80 | - `help`: Displays a list of available commands and their descriptions. 81 | - `server`: Server-related operations. 82 | - `start [--port=9615]`: Starts the server on the specified port (default: 9615). 83 | - `build`: Builds the project. 84 | - `pm2`: Manages the process with PM2. 85 | - `setup`: Sets up PM2 for the project. 86 | - `start`: Starts the service with PM2. 87 | - `stop`: Stops the service in PM2. 88 | - `restart`: Restarts the service in PM2. 89 | - `delete`: Removes the service from PM2. 90 | 91 | 3. **Running the Project with PM2**: 92 | - To set up and manage the service with PM2, start with the setup command: 93 | 94 | ```bash 95 | evolution-manager pm2 setup 96 | ``` 97 | 98 | - Then, you can start, stop, restart, or delete the service using the respective `pm2` commands in the CLI. 99 | 100 | These instructions provide a streamlined method for managing Evolution Manager across various systems, utilizing PM2 for efficient service start-up, maintenance, and control. 101 | 102 | ## Development Setup 103 | 104 | 1. **Prerequisites**: Ensure you have `yarn` installed on your system. 105 | 2. **Clone the Repository**: 106 | 107 | ```bash 108 | git clone https://github.com/gabrielpastori1/evolution-manager.git 109 | cd evolution-manager 110 | ``` 111 | 112 | 3. **Install Dependencies**: 113 | 114 | ```bash 115 | yarn install 116 | ``` 117 | 118 | 4. **Run Development Server**: 119 | 120 | ```bash 121 | yarn dev 122 | ``` 123 | 124 | This will start a local development server. You can access the app at `localhost:8080`. 125 | 126 | ## Building the Project 127 | 128 | To build the project for production, run: 129 | 130 | ```bash 131 | yarn build 132 | ``` 133 | 134 | This will create a `dist` folder with the compiled assets. 135 | 136 | ## Contributing 137 | 138 | Contributions are an essential part of the Evolution Manager project. Whether you're contributing code, suggestions, or feedback, your input is invaluable. To facilitate contributions, we have included a direct means for donations: 139 | 140 | ### Making a Donation 141 | 142 | If you wish to support the project financially, we have provided a QR code for Pix donations. Your generosity helps in maintaining and evolving this open-source tool. 143 | 144 | Pix Donation QR Code 145 | 146 | ### Contributing Code or Ideas 147 | 148 | We also welcome code contributions and innovative ideas. If you're interested in contributing in this way, please read our contributing guidelines for more information on how to get started. 149 | 150 | Your support, in any form, makes a significant difference and is greatly appreciated. Thank you for being a part of the Evolution Manager community! 151 | 152 | ## License 153 | 154 | This project is open-source and available under the [MIT License](LICENSE.md). 155 | -------------------------------------------------------------------------------- /docs/pt_br/cli.md: -------------------------------------------------------------------------------- 1 | [title]: \\ "CLI" 2 | 3 | # Evolution-Manager CLI 4 | 5 | ## Instalação 6 | 7 | Para instalar o Evolution-Manager CLI, execute o seguinte comando: 8 | 9 | ``` 10 | npm install -g evolution-manager 11 | ``` 12 | 13 | ## Comandos Disponíveis 14 | 15 | ### Geral 16 | 17 | - `help`: Exibe uma lista de comandos disponíveis. Para mais detalhes sobre cada comando, consulte este documento. 18 | 19 | ### Server 20 | 21 | - `server start [--port=9615]`: Inicia um servidor temporário no terminal, ideal para execução local. O parâmetro `--port` define a porta do servidor, sendo `9615` o valor padrão. 22 | - `server build`: Realiza o build do servidor, mas não o executa. (Atualmente sem uso específico). 23 | 24 | ### PM2 25 | 26 | O CLI interage com o PM2 para gerenciar processos do Evolution Manager. 27 | 28 | - `pm2 setup`: Configura o PM2 para hospedar o Evolution Manager. Se o PM2 não estiver instalado, o CLI o instalará automaticamente. 29 | - `pm2 start`: Inicia o processo do Evolution Manager no PM2. 30 | - `pm2 stop`: Para o processo do Evolution Manager no PM2. 31 | - `pm2 restart`: Reinicia o processo do Evolution Manager no PM2. 32 | - `pm2 delete`: Remove o processo do Evolution Manager do PM2. 33 | 34 | ## API 35 | 36 | A seção API do Evolution-Manager CLI inclui várias funções para gerenciar a instalação e as versões do Evolution Manager na API. Os comandos disponíveis são: 37 | 38 | - `setup` ou `install`: Instala o manager dentro da Evolution API no caminho `/manager`. Este comando também pode ser acessado usando a abreviação `i`. 39 | - `uninstall`: Desinstala o manager da Evolution API. 40 | - `changeVersion` ou `cv`: Altera para uma versão específica da Evolution API, seja ela mais nova ou mais antiga. Exemplo de uso: `changeVersion --v=1.5.0`. 41 | 42 | Esses comandos fornecem uma interface de linha de comando flexível e poderosa para gerenciar as versões e a configuração do manager na sua instalação da Evolution API. 43 | 44 | ## Fluxo de Uso Típico 45 | 46 | 1. Instale o CLI globalmente. 47 | 2. Utilize o comando `help` para ver a lista de comandos disponíveis. 48 | 3. Para hospedar o Evolution Manager, use os comandos sob `PM2`. 49 | 4. Use o comando `server start` para rodar um servidor temporário localmente. 50 | 5. Utilize `api setup` para interagir com o projeto "evolution-api" e configurar o manager. 51 | -------------------------------------------------------------------------------- /docs/pt_br/docker.md: -------------------------------------------------------------------------------- 1 | # Imagem Docker do Evolution Manager 2 | 3 | Este arquivo README descreve como usar a imagem Docker do Evolution Manager e configurar um domínio utilizando o [Traefik](#configurando-o-domínio-com-o-traefik) ou [NGINX](#configurando-o-domínio-com-o-nginx). 4 | 5 | ## Usando a Imagem Docker 6 | 7 | A imagem Docker do Evolution Manager permite uma instalação e atualização fáceis e automatizadas do sistema. Ao iniciar o container, a versão mais recente do Evolution Manager será baixada e instalada. 8 | 9 | ### Pré-requisitos 10 | 11 | - Docker instalado em sua máquina. 12 | - Conhecimento básico de operações do Docker. 13 | 14 | ### Executando o Container 15 | 16 | Para iniciar o container com o Evolution Manager, execute o seguinte comando: 17 | 18 | ```sh 19 | docker run -d -p 9615:9615 gabrielpastori1/evolution-manager:latest 20 | ``` 21 | 22 | Este comando executa o container em modo detached e mapeia a porta 9615 do container para a porta 9615 do host. 23 | 24 | ### Porta Exposta 25 | 26 | A imagem expõe a porta `9615`, que deve ser mapeada para a porta correspondente no host. 27 | 28 | ## Configurando o Domínio com o Traefik 29 | 30 | Para configurar um domínio e deixar o Evolution Manager acessível via web, você pode usar o Traefik como um proxy reverso. 31 | 32 | ### Pré-requisitos 33 | 34 | - Ter o Traefik configurado em seu servidor. 35 | - Possuir um domínio apontando para o servidor onde o Traefik está rodando. 36 | 37 | ### Configuração do Traefik 38 | 39 | 1. **Crie um arquivo `docker-compose.yml`** no diretório onde você deseja iniciar o Evolution Manager, com o seguinte conteúdo: 40 | 41 | ```yaml 42 | version: '3' 43 | 44 | services: 45 | evolution-manager: 46 | image: gabrielpastori1/evolution-manager:latest 47 | restart: unless-stopped 48 | ports: 49 | - "9615:9615" 50 | labels: 51 | - "traefik.enable=true" 52 | - "traefik.http.routers.evolution-manager.rule=Host(`seu-dominio.com`)" 53 | - "traefik.http.routers.evolution-manager.entrypoints=web" 54 | # Adicione outras configurações de labels conforme necessário para o Traefik 55 | 56 | networks: 57 | default: 58 | external: 59 | name: traefik_default 60 | ``` 61 | 62 | 2. **Substitua** `seu-dominio.com` pelo domínio que você deseja usar. 63 | 64 | 3. **Certifique-se** de que a rede externa especificada (`traefik_default`) corresponda à rede usada pelo Traefik em sua configuração. 65 | 66 | ### Iniciando o Serviço 67 | 68 | Com o arquivo `docker-compose.yml` configurado, inicie o serviço com o seguinte comando: 69 | 70 | ```sh 71 | docker-compose up -d 72 | ``` 73 | 74 | O Traefik automaticamente detectará o serviço e aplicará as regras definidas nas labels do container. 75 | 76 | ## Configurando o Domínio com o NGINX 77 | 78 | Se preferir usar o NGINX como um proxy reverso em vez do Traefik, siga os passos abaixo. 79 | 80 | ### Pré-requisitos 81 | 82 | - NGINX instalado no seu servidor. 83 | - Domínio apontando para o IP do seu servidor onde o NGINX está rodando. 84 | 85 | ### Configuração do NGINX 86 | 87 | 1. **Crie um Arquivo de Configuração do NGINX**: Para redirecionar as requisições do seu domínio para o container, você precisará criar um arquivo de configuração do NGINX em `/etc/nginx/conf.d/` com o seguinte conteúdo: 88 | 89 | ```nginx 90 | server { 91 | listen 80; 92 | server_name seu-dominio.com; 93 | 94 | location / { 95 | proxy_pass http://localhost:9615; 96 | proxy_http_version 1.1; 97 | proxy_set_header Upgrade $http_upgrade; 98 | proxy_set_header Connection 'upgrade'; 99 | proxy_set_header Host $host; 100 | proxy_cache_bypass $http_upgrade; 101 | } 102 | } 103 | ``` 104 | 105 | 2. **Substitua** `seu-dominio.com` pelo seu domínio real. 106 | 107 | 3. **Verifique a Configuração do NGINX**: Execute `nginx -t` para verificar se não há erros na configuração. 108 | 109 | 4. **Recarregue o NGINX**: Após verificar a configuração, recarregue o serviço do NGINX com `service nginx reload` ou `systemctl reload nginx`. 110 | 111 | Agora o NGINX redirecionará as requisições do seu domínio para a porta `9615`, onde o seu container Docker está escutando. 112 | 113 | ## Suporte e Contribuições 114 | 115 | Para suporte, dúvidas ou contribuições, abra uma issue ou envie um pull request no [repositório do GitHub](https://github.com/gabrielpastori1/evolution-manager). Sua participação é muito bem-vinda! 116 | -------------------------------------------------------------------------------- /docs/pt_br/general/node-install.md: -------------------------------------------------------------------------------- 1 | [title]: \\ "Instalar Node usando NVM" 2 | 3 | # Instalando Node.js com NVM 4 | 5 | Este guia fornece instruções passo a passo sobre como instalar o Node.js no Linux usando o NVM (Node Version Manager). 6 | 7 | ## Pré-requisitos 8 | 9 | - Acesso a um terminal no Linux. 10 | - Permissões para executar comandos de instalação (geralmente como usuário root ou com `sudo`). 11 | 12 | ## Passo 1: Instalar NVM 13 | 14 | NVM é uma ferramenta que permite gerenciar múltiplas versões do Node.js. Para instalá-lo, execute o seguinte comando no seu terminal: 15 | 16 | ```bash 17 | curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.5/install.sh | bash 18 | ``` 19 | 20 | *Nota: Você pode verificar a versão mais recente do NVM na [página do GitHub](https://github.com/nvm-sh/nvm).* 21 | 22 | Após a instalação, feche e reabra o terminal, e então execute o seguinte comando para verificar se o NVM foi instalado corretamente: 23 | 24 | ```bash 25 | nvm --version 26 | ``` 27 | 28 | ## Passo 2: Instalar Node.js 29 | 30 | Com o NVM instalado, você pode instalar o Node.js. Para instalar a versão mais recente, use o comando: 31 | 32 | ```bash 33 | nvm install node 34 | ``` 35 | 36 | Para instalar uma versão específica do Node.js, você pode fazer: 37 | 38 | ```bash 39 | nvm install 18 # substitua 18 pela versão que você quer instalar 40 | ``` 41 | 42 | Após a instalação, verifique a versão do Node.js com: 43 | 44 | ```bash 45 | node -v 46 | ``` 47 | 48 | ## Passo 3: Usar uma Versão Específica do Node.js 49 | 50 | Você pode alternar entre as versões instaladas do Node.js com o comando `nvm use`: 51 | 52 | ```bash 53 | nvm use 18 # substitua 18 pela versão que você quer usar 54 | ``` 55 | 56 | ## Conclusão 57 | 58 | Agora você tem o NVM instalado no seu sistema Linux, permitindo que você instale e gerencie múltiplas versões do Node.js. Isso é especialmente útil para desenvolvedores trabalhando em múltiplos projetos que podem requerer diferentes versões do Node.js. 59 | -------------------------------------------------------------------------------- /docs/pt_br/index.md: -------------------------------------------------------------------------------- 1 | [title]: \\ "Sobre" 2 | 3 | 4 | # Evolution Manager 5 | 6 | ## Introdução 7 | 8 | O Evolution Manager é uma ferramenta de gerenciamento open-source para a Evolution API, projetada para facilitar a administração e monitoramento de instâncias. Pode ser acessada online em [Evolution Manager](https://github.com/gabrielpastori1/evolution-manager). 9 | 10 | ## Funcionalidades 11 | 12 | - **Gerenciamento de Instâncias**: Criação, gerenciamento e exclusão de instâncias. 13 | - **Configurações de Instância**: Personalização das configurações de comportamento (por exemplo, desativar chamadas, modo sempre online), integração com webhook, RabbitMQ, WebSocket, Chatwoot e configurações do Typebot. 14 | - **Utilitários para Usuários**: Verificação de números de usuários, busca por conversas e grupos. 15 | 16 | ## Limitações 17 | 18 | - A versão hospedada na Vercel requer que o servidor tenha um certificado SSL. 19 | 20 | ## Tecnologia 21 | 22 | - O projeto é desenvolvido usando Vue.js v3 e Vuetify. 23 | 24 | ## Evolution-Manager CLI - Documentação 25 | 26 | Para informações detalhadas sobre como usar o Evolution-Manager CLI, consulte a documentação disponível nos seguintes links: 27 | 28 | 🔗 Documentação completa: [Documentação em Português](https://github.com/gabrielpastori1/evolution-manager/blob/main/docs/pt_br/cli.md) 29 | 30 | ## Imagem Docker - Documentação 31 | 32 | Para obter informações detalhadas sobre como usar a imagem Docker, incluindo configurações e exemplos, acesse a nossa documentação completa. Você encontrará instruções passo a passo, bem como dicas úteis para maximizar o uso da imagem Docker do Evolution Manager. 33 | 34 | 🔗 Documentação completa: [Documentação em Português](https://github.com/gabrielpastori1/evolution-manager/tree/main/docs/pt_br/docker.md) 35 | 36 | --- 37 | 38 | ## Auto-Hospedagem - CLI e PM2 do Evolution Manager 39 | 40 | ### Direto ao Ponto: Configuração Rápida com PM2 41 | 42 | Para instalar rapidamente o Evolution Manager globalmente e configurá-lo com o PM2, siga estes comandos: 43 | 44 | 1. **Instalar o Evolution Manager Globalmente**: 45 | 46 | ```bash 47 | npm install -g evolution-manager 48 | ``` 49 | 50 | 2. **Configurar PM2 para o Evolution Manager**: 51 | 52 | ```bash 53 | evolution-manager pm2 setup 54 | ``` 55 | 56 | Estes dois passos instalarão o CLI do Evolution Manager globalmente em seu sistema e o configurarão para funcionar com o PM2, um gerenciador de processos poderoso. 57 | 58 | ### Instalação e Configuração 59 | 60 | Esses dois passos instalarão o CLI do Evolution Manager globalmente em seu sistema e o configurarão para funcionar com o PM2, um gerenciador de processos poderoso. 61 | 62 | 1. **Instalar o Evolution Manager Globalmente**: 63 | - Certifique-se de ter o Node.js e o NPM instalados em seu sistema. 64 | - Instale o Evolution Manager globalmente usando o NPM para acessar o CLI (Interface de Linha de Comando): 65 | 66 | ```bash 67 | npm install -g evolution-manager 68 | ``` 69 | 70 | 2. **Usando o CLI**: 71 | - Após a instalação, acesse os comandos do CLI digitando `evolution-manager` em seu terminal. 72 | - Os comandos disponíveis incluem: 73 | - `help`: Exibe uma lista de comandos disponíveis e suas descrições. 74 | - `server`: Operações relacionadas ao servidor. 75 | - `start [--port=9615]`: Inicia o servidor na porta especificada (padrão: 9615). 76 | - `build`: Constrói o projeto. 77 | - `pm2`: Gerencia o processo com o PM2. 78 | - `setup`: Configura o PM2 para o projeto. 79 | - `start`: Inicia o serviço com o PM2. 80 | - `stop`: Para o serviço no PM2. 81 | - `restart`: Reinicia o serviço no PM2. 82 | - `delete`: Remove o serviço do PM2. 83 | 84 | 3. **Executando o Projeto com o PM2**: 85 | - Para configurar e gerenciar o serviço com o PM2, comece com o comando de configuração: 86 | 87 | ```bash 88 | evolution-manager pm2 setup 89 | ``` 90 | 91 | - Em seguida, você pode iniciar, parar, reiniciar ou excluir o serviço usando os respectivos comandos `pm2` no CLI. 92 | 93 | Estas instruções fornecem um método simplificado para gerenciar o Evolution Manager em vários sistemas, utilizando o PM2 para um eficiente início de serviço 94 | 95 | ## Configuração para Desenvolvimento 96 | 97 | 1. **Pré-requisitos**: Certifique-se de ter o `yarn` instalado no seu sistema. 98 | 2. **Clonar o Repositório**: 99 | 100 | ```bash 101 | git clone https://github.com/gabrielpastori1/evolution-manager.git 102 | cd evolution-manager 103 | ``` 104 | 105 | 3. **Instalar Dependências**: 106 | 107 | ```bash 108 | yarn install 109 | ``` 110 | 111 | 4. **Executar o Servidor de Desenvolvimento**: 112 | 113 | ```bash 114 | yarn dev 115 | ``` 116 | 117 | Isso iniciará um servidor de desenvolvimento local. Você pode acessar o aplicativo em `localhost:8080`. 118 | 119 | ## Construção do Projeto 120 | 121 | Para construir o projeto para produção, execute: 122 | 123 | ```bash 124 | yarn build 125 | ``` 126 | 127 | Isso criará uma pasta `dist` com os ativos compilados. 128 | 129 | ## Contribuindo 130 | 131 | As contribuições são uma parte essencial do projeto Evolution Manager. Seja contribuindo com código, sugestões ou feedback, sua participação é inestimável. Para facilitar as contribuições, incluímos um meio direto para doações: 132 | 133 | ### Fazendo uma Doação 134 | 135 | Se desejar apoiar o projeto financeiramente, disponibilizamos um QR code para doações via Pix. Sua generosidade ajuda na manutenção e evolução desta ferramenta de código aberto. 136 | 137 | QR Code para Doação Pix 138 | 139 | ### Contribuindo com Código ou Ideias 140 | 141 | Também recebemos contribuições de código e ideias inovadoras. Se você tem interesse em contribuir dessa forma, por favor, leia nossas diretrizes de contribuição para mais informações sobre como começar. 142 | 143 | Seu apoio, de qualquer forma, faz uma grande diferença e é muito apreciado. Obrigado por fazer parte da comunidade Evolution Manager! 144 | 145 | ## Licença 146 | 147 | Este projeto é de código aberto e está disponível sob a [Licença MIT](LICENSE.md). 148 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Evolution Manager 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/api/changeVersion.js: -------------------------------------------------------------------------------- 1 | const verifyEvolutionInstallation = require('../utils/verifyEvolutionInstallation.js'); 2 | const revertToVersion = require('../utils/revertToVersion.js'); 3 | 4 | module.exports = async (argv) => { 5 | const { v } = argv || {} 6 | if (!v) throw new Error('❌ Please specify a version to revert to. Example: evolution-manager api revert --v=1.5.0') 7 | 8 | const isEvolutionInstalled = verifyEvolutionInstallation(); 9 | if (!isEvolutionInstalled) return; 10 | 11 | console.log(`🔃 Reverting to Evolution-Api v${v}...`); 12 | await revertToVersion(v); 13 | console.log(`🔃 Reverted to Evolution-Api v${v} successfully`); 14 | 15 | console.log('\n🔁 Please restart the process to use the reverted version\n') 16 | }; -------------------------------------------------------------------------------- /lib/api/index.js: -------------------------------------------------------------------------------- 1 | const functions = { 2 | i: require('./setup.js'), 3 | install: require('./setup.js'), 4 | setup: require('./setup.js'), 5 | uninstall: require('./uninstall.js'), 6 | cv: require('./changeVersion.js'), 7 | changeVersion: require('./changeVersion.js'), 8 | 'migrate-to-mongo': require('./migrateToMongo/index.js'), 9 | } 10 | 11 | module.exports = async (argv) => { 12 | try { 13 | if (argv._.length === 1) throw new Error('No operation specified') 14 | const operation = argv._[1] 15 | if (!functions[operation]) throw new Error(`Unknown operation: ${operation}`) 16 | 17 | await functions[operation](argv) 18 | } catch (e) { 19 | console.error(e.message || e) 20 | process.exit(1) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/api/migrateToMongo/index.js: -------------------------------------------------------------------------------- 1 | const verifyEvolutionInstallation = require('../../utils/verifyEvolutionInstallation.js'); 2 | const cliProgress = require('cli-progress'); 3 | const inquirer = require('inquirer'); 4 | const fs = require('fs'); 5 | const path = require('path'); 6 | const colors = require('ansi-colors'); 7 | const mongoose = require('mongoose'); 8 | 9 | 10 | const migratorsFunctions = { 11 | INSTANCE: require('./migrators/instance.js'), 12 | CONTACTS: require('./migrators/contacts.js'), 13 | NEW_MESSAGE: require('./migrators/newMessage.js'), 14 | MESSAGE_UPDATE: require('./migrators/messageUpdate.js'), 15 | CHATS: require('./migrators/chats.js'), 16 | }; 17 | 18 | 19 | module.exports = async () => { 20 | const isEvolutionInstalled = verifyEvolutionInstallation(); 21 | if (!isEvolutionInstalled) return; 22 | 23 | const instancesNames = fs.readdirSync(path.join(process.cwd(), 'instances')).filter((file) => { 24 | return fs.statSync(path.join(process.cwd(), 'instances', file)).isDirectory(); 25 | }); 26 | 27 | const questions = [ 28 | { 29 | type: 'input', 30 | name: 'mongodbUrl', 31 | message: 'MongoDB url:', 32 | default: 'mongodb://admin:password@localhost:27017', 33 | }, 34 | { 35 | type: 'input', 36 | name: 'prefix', 37 | message: 'MongoDB prefix:', 38 | default: 'evolution', 39 | }, 40 | { 41 | type: 'checkbox', 42 | name: 'saveData', 43 | message: 'What data do you want to migrate?', 44 | choices: [ 45 | { 46 | name: 'Instance', 47 | value: 'INSTANCE', 48 | checked: true, 49 | }, 50 | { 51 | name: 'New Message', 52 | value: 'NEW_MESSAGE', 53 | checked: true, 54 | }, 55 | { 56 | name: 'Message Update', 57 | value: 'MESSAGE_UPDATE', 58 | checked: true, 59 | }, 60 | { 61 | name: 'Contacts', 62 | value: 'CONTACTS', 63 | checked: true, 64 | }, 65 | { 66 | name: 'Chats', 67 | value: 'CHATS', 68 | checked: true, 69 | }, 70 | ], 71 | }, 72 | { 73 | type: 'checkbox', 74 | name: 'selectedInstances', 75 | message: 'Select instances to migrate:', 76 | choices: instancesNames.map((instanceName) => { 77 | return { 78 | name: instanceName, 79 | value: instanceName, 80 | checked: true, 81 | } 82 | }), 83 | } 84 | ]; 85 | 86 | const answers = await inquirer.prompt(questions); 87 | 88 | // check if there is any data to migrate 89 | if (answers.saveData.length === 0) { 90 | console.log('🌱 No data selected to migrate!\n\n'); 91 | process.exit(0); 92 | } 93 | if (answers.selectedInstances.length === 0) { 94 | console.log('🌱 No instances selected to migrate!\n\n'); 95 | process.exit(0); 96 | } 97 | 98 | // connect to mongodb 99 | console.log('\n\n🌱 Connecting to MongoDB...'); 100 | const conn = await mongoose.createConnection(answers.mongodbUrl, { 101 | dbName: answers.prefix + '-whatsapp-api', 102 | }).asPromise(); 103 | const connInstance = answers.saveData.includes('INSTANCE') ? await mongoose.createConnection(answers.mongodbUrl, { 104 | dbName: answers.prefix + '-instances', 105 | }).asPromise() : null; 106 | console.log('🌱 Connected to MongoDB!\n\n'); 107 | 108 | const instancesBar = new cliProgress.SingleBar({ 109 | format: 'Instance: ' + colors.blue('{instanceName}') + ' |' + colors.cyan('{bar}') + '| {percentage}% || {value}/{total} Instances', 110 | }, cliProgress.Presets.shades_classic); 111 | 112 | instancesBar.start(answers.selectedInstances.length, 0); 113 | try { 114 | for (const instanceName of answers.selectedInstances) { 115 | instancesBar.update({ instanceName }); 116 | 117 | const instanceBars = new cliProgress.MultiBar({ 118 | format: '|' + colors.cyan('{bar}') + '| ' + colors.blue('{process}') + ' | {percentage}% || {value}/{total} Files', 119 | clearOnComplete: true, 120 | }, cliProgress.Presets.shades_classic); 121 | 122 | for (const migration of answers.saveData) { 123 | await migratorsFunctions[migration](instanceName, answers, instanceBars, conn, connInstance); 124 | } 125 | 126 | instanceBars.stop(); 127 | instancesBar.increment(); 128 | } 129 | } catch (err) { 130 | instancesBar.stop(); 131 | console.log(err.file); 132 | console.log(err.err); 133 | process.exit(1); 134 | } 135 | 136 | instancesBar.stop(); 137 | 138 | // disconnect from mongodb 139 | console.log('\n\n🌱 Disconnecting from MongoDB...'); 140 | await conn.close(); 141 | if (connInstance) await connInstance.close(); 142 | console.log('🌱 Disconnected from MongoDB!\n\n'); 143 | 144 | console.log('🌱 Migration completed!\n\n'); 145 | process.exit(0); 146 | }; -------------------------------------------------------------------------------- /lib/api/migrateToMongo/migrators/chats.js: -------------------------------------------------------------------------------- 1 | const FOLDER_PATH = [{ 2 | path: "/store/chats", 3 | key: "chats" 4 | }] 5 | 6 | const fs = require("fs") 7 | const path = require("path") 8 | 9 | 10 | module.exports = async (instanceName, options, progressBars, conn) => { 11 | var files = [] 12 | 13 | FOLDER_PATH.forEach(folder => { 14 | files = files.concat(getFiles(instanceName, folder)) 15 | }) 16 | const progress = progressBars.create(files.length, 0) 17 | progress.update({ process: 'Chats' }) 18 | for (const file of files) { 19 | try { 20 | const collectionName = file.key 21 | const collection = conn.collection(collectionName) 22 | 23 | const data = JSON.parse(fs.readFileSync(file.path, 'utf8')) 24 | data._id = file.path.split('\\').pop().split('.')[0] 25 | await collection.findOneAndUpdate({ _id: data._id }, { $set: data }, { upsert: true }) 26 | 27 | progress.increment() 28 | } catch (err) { 29 | progress.stop() 30 | throw { err, file } 31 | } 32 | } 33 | } 34 | 35 | function getFiles(instanceName, opts) { 36 | var files = [] 37 | const folder = opts.path || opts 38 | const folderPath = path.join(process.cwd(), folder) 39 | 40 | fs.readdirSync(folderPath).forEach(file => { 41 | const filePath = path.join(folderPath, file) 42 | if (fs.statSync(filePath).isDirectory()) { 43 | files = files.concat(getFiles(instanceName, { ...opts, path: `${folder}/${file}` })) 44 | } else if (file.includes(instanceName) || folder.includes(instanceName)) { 45 | files.push({ ...opts, path: filePath }) 46 | } 47 | }) 48 | return files 49 | } -------------------------------------------------------------------------------- /lib/api/migrateToMongo/migrators/contacts.js: -------------------------------------------------------------------------------- 1 | const FOLDER_PATH = [{ 2 | path: "/store/contacts", 3 | key: "contacts" 4 | }] 5 | 6 | const fs = require("fs") 7 | const path = require("path") 8 | 9 | 10 | module.exports = async (instanceName, options, progressBars, conn) => { 11 | var files = [] 12 | 13 | FOLDER_PATH.forEach(folder => { 14 | files = files.concat(getFiles(instanceName, folder)) 15 | }) 16 | const progress = progressBars.create(files.length, 0) 17 | progress.update({ process: 'Contacts' }) 18 | for (const file of files) { 19 | try { 20 | const collectionName = file.key 21 | const collection = conn.collection(collectionName) 22 | 23 | const data = JSON.parse(fs.readFileSync(file.path, 'utf8')) 24 | data._id = file.path.split('\\').pop().split('.')[0] 25 | await collection.findOneAndUpdate({ _id: data._id }, { $set: data }, { upsert: true }) 26 | 27 | progress.increment() 28 | } catch (err) { 29 | progress.stop() 30 | throw { err, file } 31 | } 32 | } 33 | } 34 | 35 | function getFiles(instanceName, opts) { 36 | var files = [] 37 | const folder = opts.path || opts 38 | const folderPath = path.join(process.cwd(), folder) 39 | 40 | fs.readdirSync(folderPath).forEach(file => { 41 | const filePath = path.join(folderPath, file) 42 | if (fs.statSync(filePath).isDirectory()) { 43 | files = files.concat(getFiles(instanceName, { ...opts, path: `${folder}/${file}` })) 44 | } else if (file.includes(instanceName) || folder.includes(instanceName)) { 45 | files.push({ ...opts, path: filePath }) 46 | } 47 | }) 48 | return files 49 | } -------------------------------------------------------------------------------- /lib/api/migrateToMongo/migrators/instance.js: -------------------------------------------------------------------------------- 1 | const FOLDER_PATH = [ 2 | { 3 | path: "/store/auth/apikey", 4 | key: "authentication" 5 | }, 6 | { 7 | path: "/instances", 8 | secondaryConnection: true 9 | }, 10 | { path: "/store/chamaai", key: "chamaai" }, 11 | { path: "/store/chatwoot", key: "chatwoot" }, 12 | { path: "/store/proxy", key: "proxy" }, 13 | { path: "/store/rabbitmq", key: "rabbitmq" }, 14 | { path: "/store/settings", key: "settings" }, 15 | { path: "/store/typebot", key: "typebot" }, 16 | { path: "/store/webhook", key: "webhook" }, 17 | { path: "/store/websocket", key: "websocket" }, 18 | ] 19 | 20 | const fs = require("fs") 21 | const path = require("path") 22 | 23 | 24 | module.exports = async (instanceName, options, progressBars, conn, connInstance) => { 25 | var files = [] 26 | 27 | FOLDER_PATH.forEach(folder => { 28 | files = files.concat(getFiles(instanceName, folder)) 29 | }) 30 | const progress = progressBars.create(files.length, 0) 31 | progress.update({ process: 'Instance' }) 32 | for (const file of files) { 33 | try { 34 | const collectionName = file.key || instanceName 35 | const collection = (!file.secondaryConnection ? conn : connInstance).collection(collectionName) 36 | 37 | var data; 38 | try { 39 | data = JSON.parse(fs.readFileSync(file.path, 'utf8')) 40 | } catch (err) { 41 | continue; 42 | } 43 | 44 | 45 | if (Array.isArray(data)) continue 46 | data._id = file.path.split('\\').pop().split('.')[0] 47 | await collection.findOneAndUpdate({ _id: data._id }, { $set: data }, { upsert: true }) 48 | } catch (err) { 49 | progress.stop() 50 | throw { err, file } 51 | } finally { 52 | progress.increment() 53 | } 54 | } 55 | } 56 | 57 | function getFiles(instanceName, opts) { 58 | var files = [] 59 | const folder = opts.path || opts 60 | const folderPath = path.join(process.cwd(), folder) 61 | 62 | fs.readdirSync(folderPath).forEach(file => { 63 | const filePath = path.join(folderPath, file) 64 | if (fs.statSync(filePath).isDirectory()) { 65 | files = files.concat(getFiles(instanceName, { ...opts, path: `${folder}/${file}` })) 66 | } else if (file.includes(instanceName) || opts.path.includes(instanceName)) { 67 | files.push({ ...opts, path: filePath }) 68 | } 69 | }) 70 | return files 71 | } -------------------------------------------------------------------------------- /lib/api/migrateToMongo/migrators/messageUpdate.js: -------------------------------------------------------------------------------- 1 | const FOLDER_PATH = [{ 2 | path: "/store/message-up", 3 | key: "messageUpdate" 4 | }] 5 | 6 | const fs = require("fs") 7 | const path = require("path") 8 | 9 | 10 | module.exports = async (instanceName, options, progressBars, conn) => { 11 | var files = [] 12 | 13 | FOLDER_PATH.forEach(folder => { 14 | files = files.concat(getFiles(instanceName, folder)) 15 | }) 16 | const progress = progressBars.create(files.length, 0) 17 | progress.update({ process: 'Message Update' }) 18 | for (const file of files) { 19 | try { 20 | const collectionName = file.key 21 | const collection = conn.collection(collectionName) 22 | 23 | const data = JSON.parse(fs.readFileSync(file.path, 'utf8')) 24 | data._id = file.path.split('\\').pop().split('.')[0] 25 | await collection.findOneAndUpdate({ _id: data._id }, { $set: data }, { upsert: true }) 26 | 27 | progress.increment() 28 | } catch (err) { 29 | progress.stop() 30 | throw { err, file } 31 | } 32 | } 33 | } 34 | 35 | function getFiles(instanceName, opts) { 36 | var files = [] 37 | const folder = opts.path || opts 38 | const folderPath = path.join(process.cwd(), folder) 39 | 40 | fs.readdirSync(folderPath).forEach(file => { 41 | const filePath = path.join(folderPath, file) 42 | if (fs.statSync(filePath).isDirectory()) { 43 | files = files.concat(getFiles(instanceName, { ...opts, path: `${folder}/${file}` })) 44 | } else if (file.includes(instanceName) || folder.includes(instanceName)) { 45 | files.push({ ...opts, path: filePath }) 46 | } 47 | }) 48 | return files 49 | } -------------------------------------------------------------------------------- /lib/api/migrateToMongo/migrators/newMessage.js: -------------------------------------------------------------------------------- 1 | const FOLDER_PATH = [{ 2 | path: "/store/messages", 3 | key: "messages" 4 | }] 5 | 6 | const fs = require("fs") 7 | const path = require("path") 8 | 9 | 10 | module.exports = async (instanceName, options, progressBars, conn) => { 11 | var files = [] 12 | 13 | FOLDER_PATH.forEach(folder => { 14 | files = files.concat(getFiles(instanceName, folder)) 15 | }) 16 | const progress = progressBars.create(files.length, 0) 17 | progress.update({ process: 'Messages' }) 18 | for (const file of files) { 19 | try { 20 | const collectionName = file.key 21 | const collection = conn.collection(collectionName) 22 | 23 | const data = JSON.parse(fs.readFileSync(file.path, 'utf8')) 24 | data._id = file.path.split('\\').pop().split('.')[0] 25 | await collection.findOneAndUpdate({ _id: data._id }, { $set: data }, { upsert: true }) 26 | 27 | progress.increment() 28 | } catch (err) { 29 | progress.stop() 30 | throw { err, file } 31 | } 32 | } 33 | } 34 | 35 | function getFiles(instanceName, opts) { 36 | var files = [] 37 | const folder = opts.path || opts 38 | const folderPath = path.join(process.cwd(), folder) 39 | 40 | fs.readdirSync(folderPath).forEach(file => { 41 | const filePath = path.join(folderPath, file) 42 | if (fs.statSync(filePath).isDirectory()) { 43 | files = files.concat(getFiles(instanceName, { ...opts, path: `${folder}/${file}` })) 44 | } else if (file.includes(instanceName) || folder.includes(instanceName)) { 45 | files.push({ ...opts, path: filePath }) 46 | } 47 | }) 48 | return files 49 | } -------------------------------------------------------------------------------- /lib/api/setup.js: -------------------------------------------------------------------------------- 1 | const build = require('../utils/build.js'); 2 | const fs = require('fs-extra'); 3 | const path = require('path'); 4 | const verifyEvolutionInstallation = require('../utils/verifyEvolutionInstallation.js'); 5 | 6 | module.exports = async () => { 7 | const isEvolutionInstalled = verifyEvolutionInstallation(); 8 | if (!isEvolutionInstalled) return; 9 | 10 | await build({ VITE_BASE_URL: '/manager/' }); 11 | 12 | console.time('📦 Copy dist folder to /Extras/evolution-manager'); 13 | 14 | const distFolder = path.join(__dirname, '..', '..', 'dist'); 15 | const extrasFolder = path.join(process.cwd(), 'Extras'); 16 | const evolutionManagerFolder = path.join(extrasFolder, 'evolution-manager'); 17 | 18 | if (!fs.existsSync(evolutionManagerFolder)) fs.mkdirSync(evolutionManagerFolder); 19 | fs.copySync(distFolder, evolutionManagerFolder); 20 | 21 | console.timeEnd('📦 Copy dist folder to /Extras/evolution-manager'); 22 | 23 | 24 | // Apply diff git patch 25 | console.time('📥 Apply diff git patch'); 26 | const patchPath = path.join(__dirname, './view.router.ts.patch'); 27 | const apiFile = path.join(process.cwd(), 'src', 'whatsapp', 'routers', 'view.router.ts'); 28 | // copy/replace file with patch 29 | fs.copySync(patchPath, apiFile); 30 | console.timeEnd('📥 Apply diff git patch'); 31 | 32 | 33 | console.log('\n🎉 Evolution-Api Manager installed successfully! 🎉'); 34 | console.log('🔁 Restart your Evolution-Api server to apply changes 🔁') 35 | }; -------------------------------------------------------------------------------- /lib/api/uninstall.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs-extra'); 2 | const path = require('path'); 3 | const { exec } = require('child_process'); 4 | 5 | const verifyEvolutionInstallation = require('../utils/verifyEvolutionInstallation.js'); 6 | const revertToVersion = require('../utils/revertToVersion.js'); 7 | 8 | module.exports = async () => { 9 | const isEvolutionInstalled = verifyEvolutionInstallation(); 10 | if (!isEvolutionInstalled) return; 11 | 12 | // Verify manager instalation 13 | const extrasFolder = path.join(process.cwd(), 'Extras'); 14 | const evolutionManagerIndex = path.join(extrasFolder, 'evolution-manager/index.html'); 15 | if (!fs.existsSync(evolutionManagerIndex)) throw new Error('❌ Evolution Manager installation not found. Please install it first'); 16 | 17 | 18 | const apiVersion = isEvolutionInstalled.version; 19 | 20 | // git pull force tag version 21 | console.log(`🔃 Reverting to Evolution-Api v${apiVersion}...`); 22 | await discardChanges(); 23 | await revertToVersion(apiVersion); 24 | console.log(`🔃 Reverted to Evolution-Api v${apiVersion} successfully`); 25 | 26 | console.log('\n🔁 Please restart the process to use the reverted version\n') 27 | }; 28 | 29 | function discardChanges() { 30 | return new Promise((resolve) => { 31 | exec(`git clean -f -d -q && git checkout .`, (err) => { 32 | if (err) { 33 | console.error(err) 34 | return resolve(false) 35 | } 36 | 37 | resolve(true) 38 | }) 39 | }) 40 | } 41 | 42 | -------------------------------------------------------------------------------- /lib/api/view.router.ts.patch: -------------------------------------------------------------------------------- 1 | import { Router } from 'express'; 2 | import fs from 'fs'; 3 | import mime from 'mime-types'; 4 | import path from 'path'; 5 | 6 | import { RouterBroker } from '../abstract/abstract.router'; 7 | 8 | export class ViewsRouter extends RouterBroker { 9 | constructor() { 10 | super(); 11 | const baseDir = __dirname.includes('dist') ? '../../../../' : '../../../'; 12 | const indexPath = path.join(__dirname, baseDir, 'Extras/evolution-manager', 'index.html'); 13 | const index = fs.readFileSync(indexPath); 14 | 15 | this.router.get('/*', (req, res) => { 16 | try { 17 | const pathname = req.url.split('?')[0]; 18 | 19 | // verify if url is a file in dist folder 20 | if (pathname === '/') throw {}; 21 | const filePath = path.join(__dirname, baseDir, 'Extras/evolution-manager', pathname); 22 | 23 | if (fs.existsSync(filePath)) { 24 | const contentType = mime.lookup(filePath) || 'text/plain'; 25 | res.set('Content-Type', contentType); 26 | res.end(fs.readFileSync(filePath)); 27 | return; 28 | } 29 | 30 | res.set('Content-Type', 'text/html'); 31 | res.send(index); 32 | } catch { 33 | res.set('Content-Type', 'text/html'); 34 | res.send(index); 35 | } 36 | }); 37 | } 38 | 39 | public readonly router = Router(); 40 | } 41 | -------------------------------------------------------------------------------- /lib/cli.js: -------------------------------------------------------------------------------- 1 | var argv = require('optimist').argv 2 | 3 | const { verbose, isVerbose } = require('./utils/verbose.js') 4 | 5 | const operations = { 6 | // 'create': require('./create'), 7 | 'help': require('./help'), 8 | 'server': require('./server'), 9 | 'pm2': require('./pm2'), 10 | 'api': require('./api'), 11 | } 12 | 13 | const { version } = require('../package.json') 14 | 15 | function main() { 16 | try { 17 | 18 | console.log('🖥️ evolution-manager CLI: ' + version) 19 | console.log('🖥️ Node: ' + process.version) 20 | 21 | verbose('🗣️ Verbose: ' + isVerbose) 22 | verbose('🖥️ Platform: ' + process.platform) 23 | verbose('🖥️ Architecture: ' + process.arch) 24 | verbose('🖥️ PID: ' + process.pid) 25 | verbose('🖥️ CWD: ' + process.cwd()) 26 | verbose('🖥️ argv: ' + JSON.stringify(argv)) 27 | 28 | 29 | var operation = argv._[0] 30 | 31 | if (!operation) operation = 'help' 32 | if (!operations[operation]) { 33 | 34 | console.error(' ⁉️ Unknown operation: ' + operation) 35 | operation = 'help' 36 | } 37 | verbose('🗣️ Running operation: ' + operation) 38 | operations[operation](argv) 39 | } catch (e) { 40 | console.error(e.message || e) 41 | process.exit(1) 42 | } 43 | } 44 | 45 | main() 46 | 47 | -------------------------------------------------------------------------------- /lib/help.js: -------------------------------------------------------------------------------- 1 | module.exports = () => { 2 | // Welcome message 3 | console.log(`👋 Welcome to the evolution-manager CLI! Explore the power of managing your server and API with ease.`); 4 | 5 | // Help message 6 | console.log(`📘 Here's what you can do with evolution-manager CLI:`); 7 | 8 | // Server commands 9 | console.log(`\n🚀 Server Commands:`); 10 | console.log(` help - Get help and command summaries`); 11 | console.log(` server - Manage your server`); 12 | console.log(` - start [--port=9615] - Start the server on a specific port`); 13 | console.log(` - build - Build the server environment`); 14 | 15 | // PM2 commands 16 | console.log(`\n🔄 PM2 Management:`); 17 | console.log(` pm2 - Control your PM2 processes`); 18 | console.log(` - setup - Set up a PM2 process`); 19 | console.log(` - start - Start a PM2 process`); 20 | console.log(` - stop - Stop a PM2 process`); 21 | console.log(` - restart - Restart a PM2 process`); 22 | console.log(` - delete - Delete a PM2 process`); 23 | 24 | // API commands 25 | console.log(`\n🔗 API Interaction (Run these inside the Evolution API folder):`); 26 | console.log(` api - Manage your Evolution API`); 27 | console.log(` - setup - Install the manager at /manager in the Evolution API`); 28 | console.log(` - uninstall - Uninstall the manager from the Evolution API`); 29 | console.log(` - changeVersion --v=1.5.0 - Change to a specific version of the Evolution API`); 30 | 31 | // Documentation link and disclaimer 32 | console.log(`\n📚 For complete documentation, visit: https://github.com/gabrielpastori1/evolution-manager`); 33 | console.log(`\nDisclaimer: This evolution-manager CLI project is independent and not affiliated with the evolution-api project.`); 34 | }; 35 | -------------------------------------------------------------------------------- /lib/pm2/delete.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | const detectPm2ProcessId = require('../utils/detectPm2ProcessId.js'); 3 | 4 | module.exports = async (argv, id) => { 5 | const pm2ProcessId = id || await detectPm2ProcessId(); 6 | if(pm2ProcessId === false) { 7 | console.log('⚙️ Manager process not setup') 8 | return 9 | } 10 | 11 | console.log('⚙️ Deleting PM2 process') 12 | exec(`pm2 del ${pm2ProcessId}`, (err, stdout) => { 13 | if (err) { 14 | console.error(err) 15 | return 16 | } 17 | console.log(stdout) 18 | }) 19 | 20 | console.log('🗑️ PM2 process deleted') 21 | } -------------------------------------------------------------------------------- /lib/pm2/index.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | const functions = { 4 | setup: require('./setup.js'), 5 | reset: require('./reset.js'), 6 | start: require('./start.js'), 7 | stop: require('./stop.js'), 8 | delete: require('./delete.js'), 9 | } 10 | 11 | module.exports = async (argv) => { 12 | 13 | try { 14 | if (argv._.length === 1) throw new Error('No operation specified') 15 | 16 | const operation = argv._[1] 17 | if (!functions[operation]) throw new Error(`Unknown operation: ${operation}`) 18 | 19 | await functions[operation](argv) 20 | } catch (e) { 21 | console.error(e.message || e) 22 | process.exit(1) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/pm2/reset.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | const detectPm2ProcessId = require('../utils/detectPm2ProcessId.js'); 3 | 4 | module.exports = async (argv, id) => { 5 | const pm2ProcessId = id || await detectPm2ProcessId(); 6 | if (pm2ProcessId === false) { 7 | console.log('⚙️ Manager process not setup') 8 | return 9 | } 10 | 11 | console.log('⚙️ Restarting PM2 process') 12 | exec(`pm2 restart ${pm2ProcessId}`, (err, stdout) => { 13 | if (err) { 14 | console.error(err) 15 | return 16 | } 17 | console.log(stdout) 18 | }) 19 | 20 | console.log('🚀 PM2 process restarted') 21 | } -------------------------------------------------------------------------------- /lib/pm2/setup.js: -------------------------------------------------------------------------------- 1 | const build = require('../utils/build.js'); 2 | const verifyPm2Installation = require('../utils/verifyPm2Installation.js'); 3 | const detectPm2ProcessId = require('../utils/detectPm2ProcessId.js'); 4 | const { verbose } = require('../utils/verbose') 5 | const { exec } = require('child_process') 6 | const path = require('path') 7 | 8 | module.exports = async (argv) => { 9 | const port = argv.port || 9615; 10 | 11 | 12 | await verifyPm2Installation(true); 13 | await build(); 14 | 15 | const pm2ProcessId = await detectPm2ProcessId(); 16 | 17 | if (pm2ProcessId !== false) { 18 | console.log('📦 Manager process already setup') 19 | await require('./reset.js')(argv, pm2ProcessId); 20 | return 21 | } 22 | 23 | console.log('⚙️ Starting PM2 process') 24 | console.time('⚙️ Starting PM2 process') 25 | verbose('🗣️ Port: ', port) 26 | exec(`pm2 serve dist/ ${port} --name evolution-manager --spa`, { cwd: path.join(__dirname, '..', '..') }, (err, stdout) => { 27 | if (err) { 28 | console.error(err) 29 | return 30 | } 31 | console.log(stdout) 32 | console.timeEnd('⚙️ Starting PM2 process') 33 | 34 | console.log('🚀 PM2 process started') 35 | console.log('🚀 Manager ready in port :' + port) 36 | }) 37 | } 38 | 39 | -------------------------------------------------------------------------------- /lib/pm2/start.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | const detectPm2ProcessId = require('../utils/detectPm2ProcessId.js'); 3 | 4 | module.exports = async (argv, id) => { 5 | const pm2ProcessId = id || await detectPm2ProcessId(); 6 | if (pm2ProcessId === false) { 7 | console.log('⚙️ Manager process not setup') 8 | return 9 | } 10 | 11 | console.log('⚙️ Start PM2 process') 12 | exec(`pm2 start ${pm2ProcessId}`, (err, stdout) => { 13 | if (err) { 14 | console.error(err) 15 | return 16 | } 17 | console.log(stdout) 18 | }) 19 | 20 | console.log('🚀 PM2 process started') 21 | } -------------------------------------------------------------------------------- /lib/pm2/stop.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | const detectPm2ProcessId = require('../utils/detectPm2ProcessId.js'); 3 | 4 | module.exports = async (argv, id) => { 5 | const pm2ProcessId = id || await detectPm2ProcessId(); 6 | if(pm2ProcessId === false) { 7 | console.log('⚙️ Manager process not setup') 8 | return 9 | } 10 | 11 | console.log('⚙️ Stopping PM2 process') 12 | exec(`pm2 stop ${pm2ProcessId}`, (err, stdout) => { 13 | if (err) { 14 | console.error(err) 15 | return 16 | } 17 | console.log(stdout) 18 | }) 19 | 20 | console.log('🛑 PM2 process stopped') 21 | } -------------------------------------------------------------------------------- /lib/postinstall.js: -------------------------------------------------------------------------------- 1 | const build = require('./utils/build'); 2 | 3 | async function main() { 4 | await build({ VITE_BASE_URL: '/manager/' }); 5 | } 6 | 7 | main(); -------------------------------------------------------------------------------- /lib/server.js: -------------------------------------------------------------------------------- 1 | // const pm2 = require('pm2') 2 | const mime = require('mime-types'); 3 | var http = require('http'); 4 | var fs = require('fs'); 5 | const url = require('url'); 6 | const build = require('./utils/build.js') 7 | 8 | const functions = { 9 | start, 10 | build, 11 | } 12 | 13 | module.exports = async (argv) => { 14 | try{ 15 | 16 | if (argv._.length === 1) throw new Error('No operation specified') 17 | 18 | const operation = argv._[1] 19 | if (!functions[operation]) throw new Error(`Unknown operation: ${operation}`) 20 | 21 | await functions[operation](argv) 22 | } catch (e) { 23 | console.error(e.message || e) 24 | process.exit(1) 25 | } 26 | } 27 | 28 | 29 | 30 | const path = require('path'); 31 | 32 | function startServer(argv) { 33 | const { port = 9615 } = argv || {} 34 | 35 | const index = fs.readFileSync(path.join(__dirname, '..', 'dist', 'index.html')); 36 | 37 | http.createServer(function (req, res) { 38 | try { 39 | const parsedUrl = url.parse(req.url, true); 40 | 41 | // verify if url is a file in dist folder 42 | if (parsedUrl.pathname === '/') throw {} 43 | let filePath = path.join(__dirname, '..', 'dist', parsedUrl.pathname); 44 | 45 | if (fs.existsSync(filePath)) { 46 | const contentType = mime.lookup(filePath) || 'text/plain'; 47 | res.writeHead(200, { 'Content-Type': contentType }); 48 | res.end(fs.readFileSync(filePath)); 49 | return 50 | } 51 | 52 | res.writeHead(200, { 'Content-Type': 'text/html' }); 53 | res.end(index); 54 | } catch { 55 | res.writeHead(200, { 'Content-Type': 'text/html' }); 56 | res.end(index); 57 | } 58 | }).listen(port); 59 | 60 | console.log('🚀 Server start') 61 | console.log('🚀 Server listening on port ' + port) 62 | } 63 | 64 | async function start(argv) { 65 | await build() 66 | startServer(argv) 67 | } 68 | 69 | -------------------------------------------------------------------------------- /lib/utils/build.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process') 2 | const fs = require('fs') 3 | const path = require('path') 4 | const { verbose } = require('./verbose.js') 5 | 6 | module.exports = (envs = {}) => { 7 | return new Promise((resolve, reject) => { 8 | verifyViteInstallation().then(() => { 9 | console.log('📦 Build start') 10 | console.time('📦 Build complete') 11 | const distFolder = path.join(__dirname, '..', '..', 'dist') 12 | if (fs.existsSync(distFolder)) { 13 | console.time('📦 Remove dist folder') 14 | fs.rmSync(distFolder, { recursive: true, force: true }) 15 | console.timeEnd('📦 Remove dist folder') 16 | } 17 | 18 | // pass envs to build 19 | verbose('🗣️ Build Env: ', envs) 20 | 21 | exec(`npm run build`, { env: envs, cwd: path.join(__dirname, '..', '..') }, (err, stdout) => { 22 | if (err) { 23 | console.error(err) 24 | reject(err) 25 | return 26 | } 27 | console.log(stdout) 28 | console.timeEnd('📦 Build complete') 29 | resolve() 30 | }) 31 | }) 32 | }).catch(() => { 33 | return 34 | }) 35 | } 36 | 37 | 38 | const verifyViteInstallation = () => { 39 | return new Promise((resolve, reject) => { 40 | verbose('🗣️ Verifying Vite installation') 41 | exec(`vite --v`, (err) => { 42 | if (!err) return resolve() 43 | 44 | console.log('🚨 Vite not installed, trying to install it') 45 | exec(`npm install -g vite@^4.2.0`, (err) => { 46 | if (err) { 47 | console.log('🚨 Vite installation failed') 48 | reject(err) 49 | return 50 | } 51 | 52 | console.log('🚨 Vite installed') 53 | console.log('🔁 Run the command again') 54 | reject() 55 | }) 56 | }) 57 | }) 58 | } -------------------------------------------------------------------------------- /lib/utils/detectPm2ProcessId.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | 3 | module.exports = async () => { 4 | return new Promise((resolve, reject) => { 5 | exec('pm2 jlist', async (err, stdout) => { 6 | if (err) { 7 | console.log('⚙️ PM2 is not installed'); 8 | return reject(false); 9 | } 10 | 11 | const list = JSON.parse(stdout); 12 | 13 | const process = list.find((process) => process.name === 'evolution-manager'); 14 | resolve(process ? process.pm_id : false); 15 | }); 16 | }); 17 | 18 | } -------------------------------------------------------------------------------- /lib/utils/revertToVersion.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process') 2 | 3 | module.exports = (version) => { 4 | return new Promise((resolve) => { 5 | exec(`git fetch --all && git reset --hard ${version}`, (err, stdout) => { 6 | if (err) { 7 | console.error(err) 8 | return resolve(false) 9 | } 10 | console.log(stdout) 11 | resolve(true) 12 | }) 13 | }) 14 | } -------------------------------------------------------------------------------- /lib/utils/verbose.js: -------------------------------------------------------------------------------- 1 | var argv = require('optimist').argv 2 | 3 | const isVerbose = argv.verbose || false 4 | const verbose = isVerbose ? verboseConsole : () => { }; 5 | 6 | module.exports = { 7 | verbose, 8 | isVerbose 9 | } 10 | 11 | function verboseConsole() { 12 | if (isVerbose) { 13 | console.log.apply(console, arguments) 14 | } 15 | } -------------------------------------------------------------------------------- /lib/utils/verifyEvolutionInstallation.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | 4 | module.exports = (version = "1.5.0") => { 5 | // load package.json current context 6 | const packageJsonPath = path.join(process.cwd(), 'package.json'); 7 | if (!fs.existsSync(packageJsonPath)) { 8 | console.error("🚨 package.json not found. Certify you are in the root of the Evolution-Api installation") 9 | return false 10 | } 11 | var packageJson = fs.readFileSync(packageJsonPath, 'utf8'); 12 | packageJson = JSON.parse(packageJson); 13 | 14 | 15 | // check if evolution is installed 16 | if (packageJson.name !== "evolution-api") { 17 | console.error("🚨 This is not a Evolution-API installation. Certify you are in the root of the Evolution-Api installation") 18 | return false 19 | } 20 | 21 | // verify if version is same or higher 22 | if (version) { 23 | const semver = require('semver'); 24 | if (!semver.gte(packageJson.version, version)) { 25 | console.error(`🚨 Evolution-Api version ${version} or higher is required. Please update your Evolution-Api installation`) 26 | return false 27 | } 28 | } 29 | console.log(`👍 Evolution-Api ${packageJson.version} installation found`); 30 | 31 | return { 32 | ...packageJson, 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/utils/verifyPm2Installation.js: -------------------------------------------------------------------------------- 1 | const { exec } = require('child_process'); 2 | const { verbose } = require('./verbose.js') 3 | 4 | module.exports = async (install = false) => { 5 | verbose('🗣️ Verifying PM2 installation') 6 | return new Promise((resolve, reject) => { 7 | exec('pm2 -v', async (err) => { 8 | if (err) { 9 | console.log('⚙️ PM2 is not installed') 10 | if (!install) return reject(false) 11 | const installSuccess = await installPM2() 12 | if (!installSuccess) return reject(false) 13 | resolve(true) 14 | } 15 | console.log('⚙️ PM2 is installed') 16 | resolve(true) 17 | } 18 | ) 19 | }) 20 | 21 | } 22 | 23 | function installPM2() { 24 | return new Promise((resolve) => { 25 | console.log('⚙️ Installing PM2...') 26 | console.time('⚙️ PM2 installed successfully') 27 | exec('npm install -g pm2', (err, stdout) => { 28 | console.timeEnd('⚙️ PM2 installed successfully') 29 | if (err) { 30 | console.error(err) 31 | return resolve(false) 32 | } 33 | console.log(stdout) 34 | 35 | console.log('\n\n🔁 Please restart the process to use PM2') 36 | 37 | resolve(false) 38 | }) 39 | }) 40 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "evolution-manager", 3 | "description": "Evolution Manager is an open-source interface for managing the Evolution API, simplifying the creation and administration of API instances with advanced features and diverse integrations.", 4 | "version": "0.4.13", 5 | "main": "dist", 6 | "engines": { 7 | "node": ">=16.0.0" 8 | }, 9 | "scripts": { 10 | "dev": "vite", 11 | "build": "vite build", 12 | "preview": "vite preview", 13 | "lint": "eslint . --fix --ignore-path .gitignore", 14 | "prepare": "node ./lib/postinstall.js" 15 | }, 16 | "directories": { 17 | "bin": "./bin" 18 | }, 19 | "dependencies": { 20 | "@mdi/font": "7.0.96", 21 | "@vitejs/plugin-vue": "^4.0.0", 22 | "ansi-colors": "^4.1.3", 23 | "axios": "^1.6.0", 24 | "cli-progress": "^3.12.0", 25 | "core-js": "^3.29.0", 26 | "eslint": "^8.37.0", 27 | "eslint-plugin-vue": "^9.3.0", 28 | "inquirer": "^8.0.0", 29 | "mongoose": "^8.0.3", 30 | "optimist": "^0.6.1", 31 | "pinia": "^2.0.0", 32 | "pm2": "^5.3.0", 33 | "roboto-fontface": "*", 34 | "sass": "^1.60.0", 35 | "semver": "^7.5.4", 36 | "unplugin-fonts": "^1.0.3", 37 | "vite": "^4.2.0", 38 | "vite-plugin-vuetify": "^1.0.0", 39 | "vue": "^3.2.0", 40 | "vue-i18n": "^9.8.0", 41 | "vue-router": "^4.0.0", 42 | "vue3-markdown": "^1.1.9", 43 | "vuetify": "^3.4.0" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvolutionAPI/evolution-manager/b1747d5df16b3192570b590cdd9d8d564d689ba5/public/favicon.ico -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | 9 | 23 | -------------------------------------------------------------------------------- /src/assets/chatwoot/chatwoot_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvolutionAPI/evolution-manager/b1747d5df16b3192570b590cdd9d8d564d689ba5/src/assets/chatwoot/chatwoot_api.png -------------------------------------------------------------------------------- /src/assets/chatwoot/chatwoot_api_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvolutionAPI/evolution-manager/b1747d5df16b3192570b590cdd9d8d564d689ba5/src/assets/chatwoot/chatwoot_api_1.png -------------------------------------------------------------------------------- /src/assets/chatwoot/chatwoot_api_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvolutionAPI/evolution-manager/b1747d5df16b3192570b590cdd9d8d564d689ba5/src/assets/chatwoot/chatwoot_api_2.png -------------------------------------------------------------------------------- /src/assets/chatwoot/chatwoot_api_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvolutionAPI/evolution-manager/b1747d5df16b3192570b590cdd9d8d564d689ba5/src/assets/chatwoot/chatwoot_api_3.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvolutionAPI/evolution-manager/b1747d5df16b3192570b590cdd9d8d564d689ba5/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 72 | 73 | 76 | -------------------------------------------------------------------------------- /src/components/global/EventsSelect.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 100 | -------------------------------------------------------------------------------- /src/components/global/HelpTooltip.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 33 | -------------------------------------------------------------------------------- /src/components/instance/InstanceBody.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /src/components/instance/InstanceHeader.vue: -------------------------------------------------------------------------------- 1 | 101 | 102 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /src/components/instance/message/HasWhatsapp.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 129 | -------------------------------------------------------------------------------- /src/components/instance/message/MyChats.vue: -------------------------------------------------------------------------------- 1 | 82 | 83 | 149 | 150 | 151 | -------------------------------------------------------------------------------- /src/components/instance/message/MyContacts.vue: -------------------------------------------------------------------------------- 1 | 98 | 99 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /src/components/instance/message/MyGroups.vue: -------------------------------------------------------------------------------- 1 | 95 | 96 | 167 | 168 | 169 | -------------------------------------------------------------------------------- /src/components/instance/message/OpenSendMessage.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /src/components/instance/profile/BasicInfo.vue: -------------------------------------------------------------------------------- 1 | 75 | 76 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /src/components/instance/profile/ConnectionAlert.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/components/instance/profile/ProfilePhoto.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /src/components/instance/settings/Rabbitmq.vue: -------------------------------------------------------------------------------- 1 | 61 | 62 | 160 | 161 | 162 | -------------------------------------------------------------------------------- /src/components/instance/settings/Webhook.vue: -------------------------------------------------------------------------------- 1 | 102 | 103 | 187 | 188 | 189 | -------------------------------------------------------------------------------- /src/components/instance/settings/Websocket.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /src/components/modal/About.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 75 | -------------------------------------------------------------------------------- /src/components/modal/ChatwootConfig.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 130 | -------------------------------------------------------------------------------- /src/components/modal/ConnectPhone.vue: -------------------------------------------------------------------------------- 1 | 107 | 108 | 201 | -------------------------------------------------------------------------------- /src/components/modal/Contribute.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 58 | -------------------------------------------------------------------------------- /src/components/modal/CreateInstance.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 142 | -------------------------------------------------------------------------------- /src/components/modal/GroupAddParticipantModal.vue: -------------------------------------------------------------------------------- 1 | 63 | 64 | 142 | -------------------------------------------------------------------------------- /src/components/modal/InstanceApiKey.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 79 | -------------------------------------------------------------------------------- /src/components/modal/ShareConnection.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 77 | -------------------------------------------------------------------------------- /src/helpers/copyToClipboard.js: -------------------------------------------------------------------------------- 1 | export default (value) => { 2 | if (navigator.clipboard) { 3 | navigator.clipboard.writeText(value); 4 | } else { 5 | const el = document.createElement("textarea"); 6 | el.value = value; 7 | el.setAttribute("readonly", ""); 8 | el.style.position = "absolute"; 9 | el.style.left = "-9999px"; 10 | document.body.appendChild(el); 11 | el.select(); 12 | el.setSelectionRange(0, 99999); 13 | document.execCommand("copy"); 14 | document.body.removeChild(el); 15 | } 16 | } -------------------------------------------------------------------------------- /src/helpers/deepMerge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Simple object check. 3 | * @param item 4 | * @returns {boolean} 5 | */ 6 | export function isObject(item) { 7 | return (item && typeof item === 'object' && !Array.isArray(item)); 8 | } 9 | 10 | /** 11 | * Deep merge two objects. 12 | * @param target 13 | * @param ...sources 14 | */ 15 | export function mergeDeep(target, ...sources) { 16 | if (!sources.length) return target; 17 | const source = sources.shift(); 18 | 19 | if (isObject(target) && isObject(source)) { 20 | for (const key in source) { 21 | if (isObject(source[key])) { 22 | if (!target[key]) Object.assign(target, { [key]: {} }); 23 | mergeDeep(target[key], source[key]); 24 | } else { 25 | Object.assign(target, { [key]: source[key] }); 26 | } 27 | } 28 | } 29 | 30 | return mergeDeep(target, ...sources); 31 | } -------------------------------------------------------------------------------- /src/helpers/mappers/status.js: -------------------------------------------------------------------------------- 1 | export default { 2 | close: { 3 | color: "red", 4 | text: "Desconectado", 5 | icon: "mdi-cellphone-off", 6 | }, 7 | connecting: { 8 | color: "warning", 9 | text: "Conectando", 10 | icon: "mdi-cellphone-settings", 11 | }, 12 | open: { 13 | color: "green", 14 | text: "Conectado", 15 | icon: "mdi-cellphone-nfc", 16 | }, 17 | } -------------------------------------------------------------------------------- /src/helpers/mappers/typebotStatus.js: -------------------------------------------------------------------------------- 1 | // opened, paused, closed 2 | 3 | export default { 4 | opened: { 5 | color: "green", 6 | text: "Aberto", 7 | icon: "mdi-play", 8 | }, 9 | paused: { 10 | color: "warning", 11 | text: "Pausado", 12 | icon: "mdi-pause", 13 | }, 14 | closed: { 15 | color: "red", 16 | text: "Fechado", 17 | icon: "mdi-stop", 18 | }, 19 | } -------------------------------------------------------------------------------- /src/http-common.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { useAppStore } from "@/store/app"; 3 | const appStore = useAppStore(); 4 | 5 | appStore 6 | 7 | const http = axios.create({ 8 | headers: { 9 | "Content-type": "application/json" 10 | } 11 | }); 12 | 13 | http.interceptors.request.use( 14 | config => { 15 | config.baseURL = appStore.connection.host; 16 | config.headers["apikey"] = appStore.connection.globalApiKey; 17 | 18 | // find all uri variables and replace them with the value from the params object 19 | // e.g. /instance/connect/:instance -> /instance/connect/instance1 20 | const params = Object.entries(config.params || {}); 21 | if (params.length > 0) { 22 | config.url = config.url.replace(/:(\w+)/g, (_, key) => { 23 | const value = params.find(([k]) => k === key)?.[1]; 24 | if (value) { 25 | delete config.params[key]; 26 | return value; 27 | } 28 | return _; 29 | }); 30 | 31 | if (params.instance) { 32 | const apikey = appStore.getInstanceApiKey(params.instance); 33 | if (apikey) config.headers["apikey"] = apikey; 34 | } 35 | 36 | } 37 | 38 | 39 | return config; 40 | }, 41 | error => Promise.reject(error) 42 | ); 43 | 44 | export default http; 45 | -------------------------------------------------------------------------------- /src/i18n/en.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/EvolutionAPI/evolution-manager/b1747d5df16b3192570b590cdd9d8d564d689ba5/src/i18n/en.js -------------------------------------------------------------------------------- /src/layouts/default/AppBar.vue: -------------------------------------------------------------------------------- 1 | 62 | 63 | 131 | -------------------------------------------------------------------------------- /src/layouts/default/AppFooter.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/layouts/default/Default.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | -------------------------------------------------------------------------------- /src/layouts/default/View.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /src/layouts/doc/AppBar.vue: -------------------------------------------------------------------------------- 1 | 43 | 44 | 82 | -------------------------------------------------------------------------------- /src/layouts/doc/AppFooter.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/layouts/doc/Index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /src/layouts/doc/View.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 12 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * main.js 3 | * 4 | * Bootstraps Vuetify and other plugins then mounts the App` 5 | */ 6 | 7 | // Components 8 | import App from './App.vue' 9 | 10 | // Composables 11 | import { createApp } from 'vue' 12 | 13 | // Plugins 14 | import { registerPlugins } from '@/plugins' 15 | 16 | const app = createApp(App) 17 | 18 | registerPlugins(app) 19 | 20 | app.mount('#app') 21 | -------------------------------------------------------------------------------- /src/plugins/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugins/index.js 3 | * 4 | * Automatically included in `./src/main.js` 5 | */ 6 | 7 | // Plugins 8 | import { vuetify,i18n } from './vuetify' 9 | import pinia from '../store' 10 | import router from '../router' 11 | 12 | import HelpTooltip from '@/components/global/HelpTooltip.vue' 13 | 14 | export function registerPlugins(app) { 15 | app 16 | .use(i18n) 17 | .use(vuetify) 18 | .use(router) 19 | .use(pinia) 20 | .component('HelpTooltip', HelpTooltip) 21 | 22 | } 23 | -------------------------------------------------------------------------------- /src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | /** 2 | * plugins/vuetify.js 3 | * 4 | * Framework documentation: https://vuetifyjs.com` 5 | */ 6 | 7 | // Styles 8 | import '@mdi/font/css/materialdesignicons.css' 9 | import 'vuetify/styles' 10 | 11 | // Composables 12 | import { createVuetify } from 'vuetify' 13 | import { createVueI18nAdapter } from 'vuetify/locale/adapters/vue-i18n' 14 | import { createI18n, useI18n } from 'vue-i18n' 15 | 16 | 17 | // import all files from src/i18n 18 | const messages = Object.fromEntries( 19 | Object.entries( 20 | import.meta.glob('../i18n/*.js', { eager: true }) 21 | ).map(([key, value]) => { 22 | const locale = key.match(/([A-Za-z0-9-_]+)\./i)[1] 23 | return [locale, value.default] 24 | }) 25 | ) 26 | 27 | const locale = window.localStorage.getItem('locale') || 'pt' 28 | export const i18n = createI18n({ 29 | legacy: false, // Vuetify does not support the legacy mode of vue-i18n 30 | locale, 31 | fallbackLocale: 'pt', 32 | messages, 33 | }) 34 | 35 | 36 | 37 | const defaultTheme = localStorage.getItem('theme') || 'light' 38 | export const vuetify = createVuetify({ 39 | locale: { 40 | adapter: createVueI18nAdapter({ i18n, useI18n }), 41 | }, 42 | theme: { 43 | defaultTheme, 44 | themes: { 45 | light: { 46 | colors: { 47 | primary: '#1867C0', 48 | secondary: '#5CBBF6', 49 | }, 50 | }, 51 | }, 52 | }, 53 | }) 54 | 55 | 56 | export default { 57 | vuetify, 58 | i18n 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | // Composables 2 | import { createRouter, createWebHistory } from 'vue-router' 3 | // import from base from vite compiler 4 | const BASE_URL = import.meta.env.BASE_URL 5 | 6 | const routes = [ 7 | { 8 | path: BASE_URL, 9 | component: () => import('@/layouts/default/Default.vue'), 10 | children: [ 11 | { 12 | path: '', 13 | name: 'instances', 14 | component: () => import(/* webpackChunkName: "home" */ '@/views/Home.vue'), 15 | }, 16 | { 17 | path: ':id', 18 | name: 'instance', 19 | component: () => import('@/views/Instance.vue'), 20 | } 21 | 22 | ], 23 | }, 24 | { 25 | path: BASE_URL + 'doc', 26 | component: () => import('@/layouts/doc/Index.vue'), 27 | children: [ 28 | { 29 | path: ':doc', 30 | name: 'doc', 31 | component: () => import('@/views/Doc.vue'), 32 | 33 | }, 34 | { 35 | path: '', 36 | name: 'doc.index', 37 | component: () => import('@/views/Doc.vue'), 38 | }, 39 | ] 40 | }, 41 | { 42 | path: '/:pathMatch(.*)*', 43 | redirect: BASE_URL, 44 | }, 45 | ] 46 | 47 | const router = createRouter({ 48 | history: createWebHistory(process.env.BASE_URL), 49 | routes, 50 | }) 51 | 52 | export default router 53 | -------------------------------------------------------------------------------- /src/services/instanceChatController.js: -------------------------------------------------------------------------------- 1 | 2 | import http from "../http-common"; 3 | 4 | const getAll = async (instanceName) => { 5 | return await http 6 | .get("/chat/findChats/:instance", { 7 | params: { 8 | instance: instanceName 9 | } 10 | }) 11 | .then((r) => r.data) 12 | .catch((error) => { 13 | throw error.response?.data || error.response || error; 14 | }); 15 | } 16 | 17 | const hasWhatsapp = async (instanceName, numbers) => { 18 | return await http 19 | .post("/chat/whatsappNumbers/:instance", { numbers }, { 20 | params: { 21 | instance: instanceName 22 | } 23 | }) 24 | .then((r) => r.data) 25 | .catch((error) => { 26 | throw error.response?.data || error.response || error; 27 | }); 28 | } 29 | const getContacts = async (instanceName, numbers) => { 30 | return await http 31 | .post("/chat/findContacts/:instance", { numbers }, { 32 | params: { 33 | instance: instanceName 34 | } 35 | }) 36 | .then((r) => r.data) 37 | .catch((error) => { 38 | throw error.response?.data || error.response || error; 39 | }); 40 | } 41 | 42 | const sendMessage = async (instanceName, options) => { 43 | return await http 44 | .post("/message/sendText/:instance", options, { 45 | params: { 46 | instance: instanceName 47 | } 48 | }) 49 | .then((r) => r.data) 50 | .catch((error) => { 51 | throw error.response?.data || error.response || error; 52 | }); 53 | 54 | } 55 | 56 | export default { 57 | getAll: getAll, 58 | hasWhatsapp: hasWhatsapp, 59 | getContacts: getContacts, 60 | sendMessage: sendMessage 61 | } -------------------------------------------------------------------------------- /src/services/instanceController.js: -------------------------------------------------------------------------------- 1 | import http from "../http-common"; 2 | 3 | 4 | const fetchAll = async () => { 5 | return await http 6 | .get("/instance/fetchInstances") 7 | .then((r) => r.data) 8 | .catch((error) => { 9 | throw error.response?.data || error.response || error; 10 | }); 11 | }; 12 | 13 | const create = async (data) => { 14 | return await http 15 | .post("/instance/create", data) 16 | .then((r) => r.data) 17 | .catch((error) => { 18 | throw error.response?.data || error.response || error; 19 | }); 20 | } 21 | 22 | const connect = async (instanceName) => { 23 | return await http 24 | .get("/instance/connect/:instance", { 25 | params: { 26 | instance: instanceName 27 | } 28 | }) 29 | .then((r) => r.data) 30 | .catch((error) => { 31 | throw error.response?.data || error.response || error; 32 | }); 33 | } 34 | 35 | const logout = async (instanceName) => { 36 | return await http 37 | .delete("/instance/logout/:instance", { 38 | params: { 39 | instance: instanceName 40 | } 41 | }) 42 | .then((r) => r.data) 43 | .catch((error) => { 44 | throw error.response?.data || error.response || error; 45 | }); 46 | } 47 | 48 | const restart = async (instanceName) => { 49 | return await http 50 | .put("/instance/restart/:instance", {}, { 51 | params: { 52 | instance: instanceName 53 | } 54 | }) 55 | .then((r) => r.data) 56 | .catch((error) => { 57 | throw error.response?.data || error.response || error; 58 | }); 59 | } 60 | 61 | const deleteInstance = async (instanceName) => { 62 | return await http 63 | .delete("/instance/delete/:instance", { 64 | params: { 65 | instance: instanceName 66 | } 67 | }) 68 | .then((r) => r.data) 69 | .catch((error) => { 70 | throw error.response?.data || error.response || error; 71 | }); 72 | } 73 | 74 | import settings from "./instanceSettingsController.js"; 75 | import group from "./instanceGroupController.js"; 76 | import chat from "./instanceChatController.js"; 77 | import profile from "./instanceProfileController.js"; 78 | export default { 79 | fetchAll, 80 | create, 81 | connect, 82 | logout, 83 | restart, 84 | delete: deleteInstance, 85 | ...settings, 86 | group, 87 | chat, 88 | profile, 89 | }; 90 | -------------------------------------------------------------------------------- /src/services/instanceGroupController.js: -------------------------------------------------------------------------------- 1 | 2 | import http from "../http-common"; 3 | 4 | const getAll = async (instanceName) => { 5 | return await http 6 | .get("/group/fetchAllGroups/:instance/?getParticipants=false", { 7 | params: { 8 | instance: instanceName 9 | } 10 | }) 11 | .then((r) => r.data) 12 | .catch((error) => { 13 | throw error.response?.data || error.response || error; 14 | }); 15 | } 16 | 17 | const getById = async (instanceName, groupId) => { 18 | return await http 19 | .get(`/group/findGroupInfos/:instance/?groupJid=${groupId}`, { 20 | params: { instance: instanceName } 21 | }) 22 | .then((r) => r.data) 23 | .catch((error) => { 24 | throw error.response?.data || error.response || error; 25 | }); 26 | } 27 | 28 | 29 | const updateParticipant = async (instanceName, groupId, action, participants) => { 30 | return await http 31 | .put(`/group/updateParticipant/:instance/?groupJid=${groupId}`, { 32 | action, 33 | participants // Array of participants phone numbers 34 | }, { 35 | params: { instance: instanceName } 36 | }) 37 | .then((r) => r.data) 38 | .catch((error) => { 39 | throw error.response?.data || error.response || error; 40 | }); 41 | } 42 | 43 | 44 | 45 | export default { 46 | getAll: getAll, 47 | getById: getById, 48 | updateParticipant: updateParticipant 49 | } -------------------------------------------------------------------------------- /src/services/instanceProfileController.js: -------------------------------------------------------------------------------- 1 | 2 | import http from "../http-common"; 3 | 4 | const updateName = async (instanceName, name) => { 5 | return await http 6 | .post("/chat/updateProfileName/:instance", { name }, { 7 | params: { 8 | instance: instanceName 9 | } 10 | }) 11 | .then((r) => r.data) 12 | .catch((error) => { 13 | throw error.response?.data || error.response || error; 14 | }); 15 | } 16 | 17 | const updateStatus = async (instanceName, status) => { 18 | return await http 19 | .post("/chat/updateProfileStatus/:instance", { status }, { 20 | params: { 21 | instance: instanceName 22 | } 23 | }) 24 | .then((r) => r.data) 25 | .catch((error) => { 26 | throw error.response?.data || error.response || error; 27 | }); 28 | } 29 | 30 | const getPrivacy = async (instanceName) => { 31 | return await http 32 | .get("/chat/fetchPrivacySettings/:instance", { 33 | params: { 34 | instance: instanceName 35 | } 36 | }) 37 | .then((r) => r.data) 38 | .catch((error) => { 39 | throw error.response?.data || error.response || error; 40 | }); 41 | } 42 | 43 | const updatePrivacy = async (instanceName, privacySettings) => { 44 | return await http 45 | .put("/chat/updatePrivacySettings/:instance", { privacySettings }, { 46 | params: { 47 | instance: instanceName 48 | } 49 | }) 50 | .then((r) => r.data) 51 | .catch((error) => { 52 | throw error.response?.data || error.response || error; 53 | }); 54 | } 55 | 56 | 57 | const removePicture = async (instanceName) => { 58 | return await http 59 | .delete("/chat/removeProfilePicture/:instance", { 60 | params: { 61 | instance: instanceName 62 | } 63 | }) 64 | .then((r) => r.data) 65 | .catch((error) => { 66 | throw error.response?.data || error.response || error; 67 | }); 68 | } 69 | const updatePicture = async (instanceName, picture) => { 70 | return await http 71 | .put("/chat/updateProfilePicture/:instance", { picture }, { 72 | params: { 73 | instance: instanceName 74 | } 75 | }) 76 | .then((r) => r.data) 77 | .catch((error) => { 78 | throw error.response?.data || error.response || error; 79 | }); 80 | } 81 | 82 | export default { 83 | updateName: updateName, 84 | updateStatus: updateStatus, 85 | getPrivacy: getPrivacy, 86 | updatePrivacy: updatePrivacy, 87 | removePicture: removePicture, 88 | updatePicture: updatePicture, 89 | } -------------------------------------------------------------------------------- /src/services/instanceSettingsController.js: -------------------------------------------------------------------------------- 1 | 2 | import http from "../http-common"; 3 | 4 | const findOptions = async (instanceName) => { 5 | return await http 6 | .get("/settings/find/:instance", { 7 | params: { 8 | instance: instanceName 9 | } 10 | }) 11 | .then((r) => r.data) 12 | .catch((error) => { 13 | throw error.response?.data || error.response || error; 14 | }); 15 | } 16 | 17 | const setOptions = async (instanceName, data) => { 18 | return await http 19 | .post("/settings/set/:instance", data, { 20 | params: { 21 | instance: instanceName 22 | } 23 | }) 24 | .then((r) => r.data) 25 | .catch((error) => { 26 | throw error.response?.data || error.response || error; 27 | }); 28 | } 29 | 30 | const findWebhook = async (instanceName) => { 31 | return await http 32 | .get("/webhook/find/:instance", { 33 | params: { 34 | instance: instanceName 35 | } 36 | }) 37 | .then((r) => r.data) 38 | .catch((error) => { 39 | throw error.response?.data || error.response || error; 40 | }); 41 | } 42 | 43 | const setWebhook = async (instanceName, data) => { 44 | return await http 45 | .post("/webhook/set/:instance", data, { 46 | params: { 47 | instance: instanceName 48 | } 49 | }) 50 | .then((r) => r.data) 51 | .catch((error) => { 52 | throw error.response?.data || error.response || error; 53 | }); 54 | } 55 | 56 | const findWebsocket = async (instanceName) => { 57 | return await http 58 | .get("/websocket/find/:instance", { 59 | params: { instance: instanceName } 60 | }) 61 | .then((r) => r.data) 62 | .catch((error) => { 63 | throw error.response?.data || error.response || error; 64 | }); 65 | } 66 | 67 | const setWebsocket = async (instanceName, data) => { 68 | return await http 69 | .post("/websocket/set/:instance", data, { 70 | params: { instance: instanceName } 71 | }) 72 | .then((r) => r.data) 73 | .catch((error) => { 74 | throw error.response?.data || error.response || error; 75 | }); 76 | } 77 | 78 | const findRabbitmq = async (instanceName) => { 79 | return await http 80 | .get("/rabbitmq/find/:instance", { 81 | params: { instance: instanceName } 82 | }) 83 | .then((r) => r.data) 84 | .catch((error) => { 85 | throw error.response?.data || error.response || error; 86 | }); 87 | } 88 | 89 | const setRabbitmq = async (instanceName, data) => { 90 | return await http 91 | .post("/rabbitmq/set/:instance", data, { 92 | params: { instance: instanceName } 93 | }) 94 | .then((r) => r.data) 95 | .catch((error) => { 96 | throw error.response?.data || error.response || error; 97 | }); 98 | } 99 | 100 | const findChatwoot = async (instanceName) => { 101 | return await http 102 | .get("/chatwoot/find/:instance", { 103 | params: { instance: instanceName } 104 | }) 105 | .then((r) => r.data) 106 | .catch((error) => { 107 | throw error.response?.data || error.response || error; 108 | }); 109 | } 110 | 111 | const setChatwoot = async (instanceName, data) => { 112 | return await http 113 | .post("/chatwoot/set/:instance", data, { 114 | params: { instance: instanceName } 115 | }) 116 | .then((r) => r.data) 117 | .catch((error) => { 118 | throw error.response?.data || error.response || error; 119 | }); 120 | } 121 | 122 | const findTypebot = async (instanceName) => { 123 | return await http 124 | .get("/typebot/find/:instance", { 125 | params: { instance: instanceName } 126 | }) 127 | .then((r) => r.data) 128 | .catch((error) => { 129 | throw error.response?.data || error.response || error; 130 | }); 131 | } 132 | 133 | const setTypebot = async (instanceName, data) => { 134 | return await http 135 | .post("/typebot/set/:instance", data, { 136 | params: { instance: instanceName } 137 | }) 138 | .then((r) => r.data) 139 | .catch((error) => { 140 | throw error.response?.data || error.response || error; 141 | }); 142 | } 143 | 144 | const changeTypebotStatus = async (instanceName, data) => { 145 | return await http 146 | .post("/typebot/changeStatus/:instance", data, { 147 | params: { instance: instanceName } 148 | }) 149 | .then((r) => r.data) 150 | .catch((error) => { 151 | throw error.response?.data || error.response || error 152 | }) 153 | } 154 | 155 | export default { 156 | options: { 157 | get: findOptions, 158 | set: setOptions, 159 | }, 160 | 161 | webhook: { 162 | get: findWebhook, 163 | set: setWebhook, 164 | }, 165 | websocket: { 166 | get: findWebsocket, 167 | set: setWebsocket, 168 | }, 169 | rabbitmq: { 170 | get: findRabbitmq, 171 | set: setRabbitmq, 172 | }, 173 | chatwoot: { 174 | get: findChatwoot, 175 | set: setChatwoot, 176 | }, 177 | typebot: { 178 | get: findTypebot, 179 | set: setTypebot, 180 | changeStatus: changeTypebotStatus, 181 | } 182 | } -------------------------------------------------------------------------------- /src/store/doc.js: -------------------------------------------------------------------------------- 1 | // Utilities 2 | import { defineStore } from 'pinia' 3 | 4 | 5 | export const useDocStore = defineStore('doc', { 6 | getters: { 7 | lang: (state) => state.language, 8 | }, 9 | state: () => ({ 10 | language: 'pt_br', 11 | languages: [], 12 | docs: {}, 13 | }), 14 | 15 | actions: { 16 | async setLang(lang) { 17 | this.language = lang; 18 | }, 19 | async loadDocs() { 20 | try { 21 | const { languages, docs } = getFileTree(); 22 | this.languages = languages; 23 | this.docs = docs; 24 | } catch (error) { 25 | console.log(error); 26 | } 27 | }, 28 | async loadDoc(path) { 29 | try { 30 | const { language } = this; 31 | const doc = this.docs[path] 32 | const content = doc[language].content 33 | return { 34 | content, 35 | language, 36 | }; 37 | } catch (error) { 38 | console.log(error); 39 | throw new Error('Documento não encontrado'); 40 | } 41 | } 42 | } 43 | }) 44 | 45 | // Function to get the file tree from @doc 46 | function getFileTree() { 47 | const tree = import.meta.glob('@docs/**/*.{md,mdx}', { as: 'raw', eager: true }) 48 | const docsFiles = {} 49 | const languages = new Set() 50 | 51 | Object.entries(tree).forEach(([path, imprt]) => { 52 | const [, , lang, ...rest] = path.split('/') 53 | languages.add(lang) 54 | 55 | const filename = rest.join('/').replace(/\.mdx?$/, '') 56 | docsFiles[filename] = docsFiles[filename] || {} 57 | 58 | const vars = extractVars(imprt); 59 | 60 | docsFiles[filename][lang] = { 61 | path, 62 | filename, 63 | content: imprt, 64 | ...vars, 65 | } 66 | }) 67 | 68 | return { 69 | languages: Array.from(languages), 70 | docs: docsFiles, 71 | } 72 | } 73 | 74 | 75 | function extractVars(content) { 76 | const regex = /\[([a-zA-Z]+)\]: \\\\ "(.*)"/g; 77 | const vars = {}; 78 | let m; 79 | 80 | while ((m = regex.exec(content)) !== null) { 81 | if (m.index === regex.lastIndex) { 82 | regex.lastIndex++; 83 | } 84 | 85 | vars[m[1]] = m[2]; 86 | } 87 | return vars; 88 | } -------------------------------------------------------------------------------- /src/store/index.js: -------------------------------------------------------------------------------- 1 | // Utilities 2 | import { createPinia } from 'pinia' 3 | 4 | export default createPinia() 5 | -------------------------------------------------------------------------------- /src/styles/settings.scss: -------------------------------------------------------------------------------- 1 | /** 2 | * src/styles/settings.scss 3 | * 4 | * Configures SASS variables and Vuetify overwrites 5 | */ 6 | 7 | // https://vuetifyjs.com/features/sass-variables/` 8 | // @use 'vuetify/settings' with ( 9 | // $color-pack: false 10 | // ); 11 | -------------------------------------------------------------------------------- /src/views/Doc.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 77 | 78 | 84 | -------------------------------------------------------------------------------- /src/views/Instance.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 60 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }] 3 | } -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | // Plugins 2 | import vue from '@vitejs/plugin-vue' 3 | import vuetify, { transformAssetUrls } from 'vite-plugin-vuetify' 4 | import ViteFonts from 'unplugin-fonts/vite' 5 | 6 | // Utilities 7 | import { defineConfig, loadEnv } from 'vite' 8 | import { fileURLToPath, URL } from 'node:url' 9 | 10 | // https://vitejs.dev/config/ 11 | export default defineConfig(({ command, mode }) => { 12 | const env = loadEnv(mode, process.cwd(), '') 13 | const BASE_URL = env.VITE_BASE_URL || '/' 14 | 15 | return { 16 | plugins: [ 17 | vue({ 18 | template: { transformAssetUrls } 19 | }), 20 | vuetify({ 21 | autoImport: true, 22 | styles: { 23 | configFile: 'src/styles/settings.scss', 24 | }, 25 | }), 26 | ViteFonts({ 27 | google: { 28 | families: [{ 29 | name: 'Roboto', 30 | styles: 'wght@100;300;400;500;700;900', 31 | }], 32 | }, 33 | }), 34 | ], 35 | define: { 'process.env': {} }, 36 | base: BASE_URL, 37 | 38 | resolve: { 39 | alias: { 40 | '@': fileURLToPath(new URL('./src', import.meta.url)), 41 | '@docs': fileURLToPath(new URL('./docs', import.meta.url)) 42 | }, 43 | extensions: [ 44 | '.js', 45 | '.json', 46 | '.jsx', 47 | '.mjs', 48 | '.ts', 49 | '.tsx', 50 | '.vue', 51 | ], 52 | }, 53 | server: { 54 | port: 3000, 55 | }, 56 | } 57 | }) 58 | --------------------------------------------------------------------------------