Lovable sync 1777152806#31
Conversation
X-Lovable-Edit-ID: edt-01c46b8e-ac19-4fb3-91ec-301840140d0c Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com>
X-Lovable-Edit-ID: edt-aa87ae41-6fe7-418d-85ab-46cad5ff2c67 Co-authored-by: adm01-debug <231131902+adm01-debug@users.noreply.github.com>
|
Warning Rate limit exceeded
To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This PR adjusts the QR-code TTL handling for Evolution connections by adding a history-based TTL inference fallback and persisting TTL diagnostics into qr_attempts.metadata, while also simplifying/removing some QR-related UI/components and associated tests.
Changes:
- Add
inferTtlFromHistory(pure function) + unit tests to infer QR TTL from recentqr_attempts.metadatawhen the Evolution API doesn’t provide TTL. - Extend
useConnectionsManagerto (a) detect TTL with provenance/raw value, (b) optionally infer TTL via recent history, and (c) record TTL diagnostics intoqr_attempts.metadata. - Remove
qrAutoRefreshhelper + tests, and removeRefreshQrButton/QrTtlBadgecomponents (and tests), simplifying the refresh button inConnectionsView.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| src/hooks/useConnectionsManager.ts | Adds TTL detection struct, history inference query, and metadata recording; inlines auto-refresh decision logic. |
| src/hooks/connections/qrTtlFallback.ts | New pure TTL inference helper for fallback based on historical samples. |
| src/hooks/connections/qrAutoRefresh.ts | Removed previously testable auto-refresh decision helper. |
| src/hooks/connections/tests/qrTtlFallback.test.ts | Adds unit tests for TTL inference helper. |
| src/hooks/connections/tests/qrAutoRefresh.test.ts | Removes unit tests for auto-refresh decision logic. |
| src/components/connections/ConnectionsView.tsx | Removes TTL badge + custom refresh button and replaces with a simpler outline button. |
| src/components/connections/RefreshQrButton.tsx | Removed (previously provided cooldown/stabilization/diagnostics UX). |
| src/components/connections/tests/RefreshQrButton.test.tsx | Removed tests for the deleted refresh button behavior. |
| src/components/connections/QrTtlBadge.tsx | Removed TTL source/TTL display badge component. |
Comments suppressed due to low confidence (1)
src/hooks/useConnectionsManager.ts:927
- A lógica de decisão do auto-refresh foi inlinada no
useEffecte os testes unitários anteriores para essa decisão foram removidos. Como esse agendamento é sensível a edge-cases de tempo (delay <= 0, dialog fechado, troca de attemptId), recomendo reintroduzir um helper puro (como era oevaluateAutoRefresh) e cobri-lo com testes, ou adicionar novos testes que validem o comportamento equivalente.
// Auto-refresh: regenerate the QR ~5s before it expires (at 55s of the 60s TTL)
// so the user never has to manually click "Atualizar" mid-scan.
//
// Strict guard: only schedules and only fires while the dialog is OPEN and the
// current status is 'pending' (status local já reconciliado com a fonte de
// verdade `qr_attempts.status` pelo effect acima). Se o status no banco virar
// `connected`/`error`/`expired`, o effect de reconciliação atualiza
// `qrCodeDialog.status`, fazendo este effect re-rodar e cancelar o timer
// pendente via cleanup — assim o auto-refresh nunca dispara contra um QR já
// aprovado ou falho no servidor.
useEffect(() => {
if (!qrCodeDialog.open) {
log.debug('[qr-auto-refresh] not_scheduled', { reason: 'dialog_closed' });
return;
}
if (qrCodeDialog.status !== 'pending') {
log.debug('[qr-auto-refresh] not_scheduled', { reason: 'status_not_pending', status: qrCodeDialog.status });
return;
}
if (!qrCodeDialog.expiresAt) {
log.debug('[qr-auto-refresh] not_scheduled', { reason: 'no_expires_at' });
return;
}
const delay = qrCodeDialog.expiresAt - 5_000 - Date.now();
if (delay <= 0) {
log.debug('[qr-auto-refresh] not_scheduled', { reason: 'already_past_window', delay });
return;
}
log.info('[qr-auto-refresh] scheduled', { delayMs: delay, attemptId: qrCodeDialog.attemptId });
const scheduledForAttempt = qrCodeDialog.attemptId;
const generationAtSchedule = dialogGenRef.current;
const timer = setTimeout(() => {
// Defesa extra contra race condition: se o usuário fechou o diálogo
// entre o agendamento e o disparo, dialogGenRef avançou — abortar.
if (dialogGenRef.current !== generationAtSchedule) {
log.info('[qr-auto-refresh] fire_aborted', { reason: 'dialog_closed_before_fire', attemptId: scheduledForAttempt });
return;
}
// Re-check the latest dialog state at fire time — the props captured in
// closure may be stale if the user already closed the dialog or another
// refresh raced ahead. We use the functional setter to read the freshest
// state without adding it to the dependency array.
setQrCodeDialog((current) => {
if (
current.open &&
current.status === 'pending' &&
current.attemptId === scheduledForAttempt
) {
log.info('[qr-auto-refresh] firing', { attemptId: scheduledForAttempt });
void handleRefreshQrCode();
} else {
log.info('[qr-auto-refresh] fire_skipped', {
reason: !current.open ? 'dialog_closed' : current.status !== 'pending' ? 'status_changed' : 'attempt_changed',
currentStatus: current.status,
currentAttemptId: current.attemptId,
scheduledForAttempt,
});
}
return current;
});
}, delay);
return () => clearTimeout(timer);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [qrCodeDialog.open, qrCodeDialog.status, qrCodeDialog.expiresAt, qrCodeDialog.attemptId]);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try { | ||
| const ttlEffectiveSeconds = Math.round(ttl.ttlMs / 1000); | ||
| await supabase | ||
| .from('qr_attempts') | ||
| .update({ | ||
| metadata: { | ||
| ttl_detected_seconds: ttl.rawSeconds, | ||
| ttl_effective_seconds: ttlEffectiveSeconds, | ||
| ttl_source: ttl.source, | ||
| expires_at: new Date(expiresAtMs).toISOString(), | ||
| recorded_at: new Date().toISOString(), | ||
| }, | ||
| }) | ||
| .eq('id', attemptId); | ||
| log.info('[qr-attempt] ttl_recorded', { |
There was a problem hiding this comment.
O supabase.from('qr_attempts').update(...).eq(...) não lança exceção quando falha; ele retorna { error }. Hoje recordQrAttemptTtl só tem try/catch e não checa error, então falhas de RLS/rede podem passar silenciosamente. Capture o retorno e faça early-return/log quando error vier preenchido (idealmente também logar quando data vier vazio).
| import { ConnectionCard } from './ConnectionCard'; | ||
| import { DegradedQuickActions } from './DegradedQuickActions'; | ||
| import { QrCountdown } from './QrCountdown'; | ||
| import { QrTtlBadge } from './QrTtlBadge'; | ||
| import { QrAttemptHistory } from './QrAttemptHistory'; | ||
| import { RefreshQrButton } from './RefreshQrButton'; | ||
| import { IdempotencyMissBanner } from './IdempotencyMissBanner'; |
There was a problem hiding this comment.
Este PR removeu componentes/UX (ex.: QrTtlBadge, RefreshQrButton) e também testes associados, mas a descrição do PR está vazia e não menciona essas remoções. Para facilitar revisão e evitar regressões não intencionais, documente explicitamente no PR o motivo/impacto dessas remoções e quais comportamentos esperados mudaram (ex.: cooldown/diagnóstico do refresh).
| /** | ||
| * Persiste no `qr_attempts.metadata` o TTL detectado e o efetivo (em segundos) | ||
| * usados para calcular o `expiresAt`. Usado pelo time comercial para | ||
| * correlacionar falhas de pareamento com o tempo de rotação real entregue | ||
| * pela Evolution API. | ||
| * | ||
| * Faz merge não-destrutivo via spread no payload — qualquer outro campo de | ||
| * metadata adicionado no futuro continua intacto. | ||
| */ | ||
| const recordQrAttemptTtl = async ( | ||
| attemptId: string | null, | ||
| ttl: DetectedQrTtl, | ||
| expiresAtMs: number, | ||
| ) => { | ||
| if (!attemptId) return; | ||
| try { | ||
| const ttlEffectiveSeconds = Math.round(ttl.ttlMs / 1000); | ||
| await supabase | ||
| .from('qr_attempts') | ||
| .update({ | ||
| metadata: { | ||
| ttl_detected_seconds: ttl.rawSeconds, | ||
| ttl_effective_seconds: ttlEffectiveSeconds, | ||
| ttl_source: ttl.source, | ||
| expires_at: new Date(expiresAtMs).toISOString(), | ||
| recorded_at: new Date().toISOString(), | ||
| }, | ||
| }) |
There was a problem hiding this comment.
recordQrAttemptTtl afirma fazer “merge não-destrutivo” na metadata, mas o .update({ metadata: { ... } }) substitui o JSON inteiro (jsonb) e pode apagar campos já existentes em qr_attempts.metadata. Ajuste a implementação para realmente mesclar (ex.: ler metadata atual e fazer spread, ou usar um merge no lado do Postgres via jsonb_set/||), ou então corrija o comentário para refletir que é overwrite completo.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8191c2f96b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| .from('qr_attempts') | ||
| .select('metadata') | ||
| .eq('instance_id', instanceId) |
There was a problem hiding this comment.
Run TTL inference where qr_attempts SELECT is allowed
This history lookup is executed in the client, but the qr_attempts SELECT policy only allows admins/supervisors (see supabase/migrations/20260423111614_2c3337b5-0191-432c-ab25-0fd708ff1d34.sql, lines 25-28). For authenticated users outside those roles, this call will always hit the error branch and fall back to the fixed default TTL, so the new inference path never actually works in that context. Consider moving the read to a privileged RPC/Edge Function or granting scoped read access for a user's own attempts.
Useful? React with 👍 / 👎.
🛑 Cannot be folded into the umbrella merge PR #32This branch has no common ancestor with current The newer Lovable sync #30 ( Recommendation:
Generated by Claude Code |
📝 Descrição
🎯 Tipo de Mudança
📷 Screenshots (se aplicável)
🧪 Testes Realizados
npm run test)npm run test:e2e)✅ Checklist
🔗 Issues Relacionadas