feat: show commit hash in footer and implement auto server health check for AppWPP

This commit is contained in:
2026-10-15 14:41:15 -03:00
parent d3b7dcbc1e
commit d8500cf433
4 changed files with 154 additions and 7 deletions
+7 -1
View File
@@ -8,7 +8,8 @@ import {
Lock, Lock,
Loader2, Loader2,
MessageSquare, MessageSquare,
Bookmark Bookmark,
GitCommit
} from 'lucide-react'; } from 'lucide-react';
import Header from './components/Header'; import Header from './components/Header';
import SecurityBadge from './components/SecurityBadge'; import SecurityBadge from './components/SecurityBadge';
@@ -251,6 +252,11 @@ export default function App() {
<span className="footer-shield"> <span className="footer-shield">
<ShieldCheck size={14} /> 100% no cliente (Executa em qualquer navegador) <ShieldCheck size={14} /> 100% no cliente (Executa em qualquer navegador)
</span> </span>
<span>•</span>
<span className="footer-commit" title="Versão do commit da aplicação">
<GitCommit size={14} className="text-cyan" />
<span>Commit: <code className="commit-hash-pill">{typeof __COMMIT_HASH__ !== 'undefined' ? __COMMIT_HASH__ : 'dev'}</code></span>
</span>
</div> </div>
</div> </div>
</footer> </footer>
+76 -5
View File
@@ -14,7 +14,8 @@ import {
AlertCircle, AlertCircle,
CheckCircle2, CheckCircle2,
Info, Info,
Edit2 Edit2,
RefreshCw
} from 'lucide-react'; } from 'lucide-react';
import { getStoredServers, saveServers } from '../../utils/appWppStorage'; import { getStoredServers, saveServers } from '../../utils/appWppStorage';
import { import {
@@ -24,7 +25,9 @@ import {
checkSessionStatus, checkSessionStatus,
clearSessionData, clearSessionData,
generateToken, generateToken,
ensureQRPrefix ensureQRPrefix,
testServerConnection,
listAllServerSessions
} from '../../utils/wppConnectApi'; } from '../../utils/wppConnectApi';
import WppSessionCard from './WppSessionCard'; import WppSessionCard from './WppSessionCard';
import ModalServer from './ModalServer'; import ModalServer from './ModalServer';
@@ -91,6 +94,63 @@ export default function AppWPP() {
}; };
const activeServer = servers.find((s) => s.id === activeServerId) || null; const activeServer = servers.find((s) => s.id === activeServerId) || null;
const [isCheckingServer, setIsCheckingServer] = useState(false);
const checkServerOnlineStatus = async (serverToCheck) => {
const srv = serverToCheck || servers.find((s) => s.id === activeServerId) || activeServer;
if (!srv || !srv.baseUrl || !srv.secretKey) return;
setIsCheckingServer(true);
try {
const res = await testServerConnection(srv.baseUrl, srv.secretKey);
const isOnline = res.ok === true;
updateServersState((prevServers) =>
prevServers.map((s) => (s.id === srv.id ? { ...s, online: isOnline } : s))
);
// Se estiver online, sincroniza o status das sessões já ativas no servidor
if (isOnline) {
try {
const sessionsOnServer = await listAllServerSessions(srv);
if (Array.isArray(sessionsOnServer)) {
updateServersState((prevServers) =>
prevServers.map((s) => {
if (s.id !== srv.id) return s;
const updatedSessions = (s.sessions || []).map((sess) => {
const match = sessionsOnServer.find((x) =>
x === sess.name || x?.name === sess.name || x?.session === sess.name
);
if (match) {
const statusStr = typeof match === 'string' ? 'connected' : (match.status || 'connected');
const isConn = statusStr === 'CONNECTED' || statusStr === 'connected' || statusStr === true;
return { ...sess, status: isConn ? 'connected' : sess.status };
}
return sess;
});
return { ...s, sessions: updatedSessions };
})
);
}
} catch (e) {}
}
} catch (e) {
updateServersState((prevServers) =>
prevServers.map((s) => (s.id === srv.id ? { ...s, online: false } : s))
);
} finally {
setIsCheckingServer(false);
}
};
// Checa automaticamente o status do servidor ativo na inicialização e ao alternar
useEffect(() => {
if (activeServerId && servers.length > 0) {
const srv = servers.find((s) => s.id === activeServerId);
if (srv) {
checkServerOnlineStatus(srv);
}
}
}, [activeServerId, servers.length]);
// Servidor CRUD // Servidor CRUD
const handleSaveServer = (serverData) => { const handleSaveServer = (serverData) => {
@@ -415,9 +475,20 @@ export default function AppWPP() {
<div className="wpp-server-title-box"> <div className="wpp-server-title-box">
<div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}> <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
<h2 className="wpp-view-server-name">{activeServer.name}</h2> <h2 className="wpp-view-server-name">{activeServer.name}</h2>
<span className={`wpp-badge-status ${activeServer.online ? 'badge-online' : 'badge-offline'}`}> <div className="wpp-status-wrapper">
{activeServer.online ? 'Online' : 'Offline'} <span className={`wpp-badge-status ${isCheckingServer ? 'badge-checking' : (activeServer.online ? 'badge-online' : 'badge-offline')}`}>
</span> {isCheckingServer ? 'Verificando...' : (activeServer.online ? 'Online' : 'Offline')}
</span>
<button
type="button"
className="btn-refresh-status"
title="Verificar status do servidor agora"
onClick={() => checkServerOnlineStatus(activeServer)}
disabled={isCheckingServer}
>
<RefreshCw size={12} className={isCheckingServer ? 'animate-spin' : ''} />
</button>
</div>
</div> </div>
<span className="wpp-view-server-url">{activeServer.baseUrl}</span> <span className="wpp-view-server-url">{activeServer.baseUrl}</span>
</div> </div>
+54
View File
@@ -1262,6 +1262,24 @@ body {
color: #34d399; color: #34d399;
} }
.footer-commit {
display: inline-flex;
align-items: center;
gap: 0.35rem;
color: var(--text-secondary);
}
.commit-hash-pill {
font-family: var(--font-mono);
background: rgba(14, 165, 233, 0.12);
border: 1px solid rgba(14, 165, 233, 0.25);
color: #38bdf8;
padding: 0.1rem 0.45rem;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
}
/* Utilities */ /* Utilities */
.text-cyan { color: var(--accent-cyan); } .text-cyan { color: var(--accent-cyan); }
.text-emerald { color: var(--accent-emerald); } .text-emerald { color: var(--accent-emerald); }
@@ -1640,6 +1658,42 @@ body {
border: 1px solid rgba(100, 116, 139, 0.3); border: 1px solid rgba(100, 116, 139, 0.3);
} }
.badge-checking {
background: rgba(234, 179, 8, 0.15);
color: #facc15;
border: 1px solid rgba(234, 179, 8, 0.3);
}
.wpp-status-wrapper {
display: inline-flex;
align-items: center;
gap: 0.4rem;
}
.btn-refresh-status {
background: rgba(255, 255, 255, 0.05);
border: 1px solid var(--border-color);
color: var(--text-muted);
border-radius: 6px;
padding: 0.2rem 0.35rem;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
}
.btn-refresh-status:hover:not(:disabled) {
color: #38bdf8;
border-color: rgba(56, 189, 248, 0.4);
background: rgba(56, 189, 248, 0.1);
}
.btn-refresh-status:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.wpp-server-actions-group { .wpp-server-actions-group {
display: flex; display: flex;
align-items: center; align-items: center;
+17 -1
View File
@@ -1,9 +1,25 @@
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite' import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { execSync } from 'child_process'
let commitHash = process.env.COMMIT_REF
? process.env.COMMIT_REF.slice(0, 7)
: '';
if (!commitHash) {
try {
commitHash = execSync('git rev-parse --short HEAD').toString().trim();
} catch (e) {
commitHash = 'dev';
}
}
// https://vite.dev/config/ // https://vite.dev/config/
export default defineConfig({ export default defineConfig({
plugins: [react()], plugins: [react()],
define: {
__COMMIT_HASH__: JSON.stringify(commitHash)
},
server: { server: {
proxy: { proxy: {
'/api-wpp': { '/api-wpp': {