Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,9 @@ export function SecretsManagerHealthPanel({ className }: { className?: string })
{boot?.requestId && (
<button
type="button"
onClick={() => copyToClipboard(boot.requestId, 'request_id copiado')}
onClick={() =>
boot.requestId && copyToClipboard(boot.requestId, 'request_id copiado')
}
className="ml-auto inline-flex items-center gap-1 font-mono text-[11px] text-muted-foreground hover:text-foreground"
title="Copiar request_id para correlacionar com edge logs"
>
Expand Down
12 changes: 8 additions & 4 deletions src/components/admin/connections/__tests__/ConnectionUI.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,13 @@ vi.mock('@/hooks/intelligence', () => ({
}));

describe('ConnectionsOverviewTable Interações e Acessibilidade', () => {
const useAuthMock = vi.mocked(useAuth);
const useConnectionsOverviewMock = vi.mocked(useConnectionsOverview);
const useConnectionTesterMock = vi.mocked(useConnectionTester);
const useAuthMock = vi.mocked(useAuth) as unknown as ReturnType<typeof vi.fn>;
const useConnectionsOverviewMock = vi.mocked(useConnectionsOverview) as unknown as ReturnType<
typeof vi.fn
>;
const useConnectionTesterMock = vi.mocked(useConnectionTester) as unknown as ReturnType<
typeof vi.fn
>;
Comment on lines +45 to +51

const mockRows = [
{
Expand All @@ -66,7 +70,7 @@ describe('ConnectionsOverviewTable Interações e Acessibilidade', () => {
loading: false,
refresh: vi.fn(),
});
useConnectionTesterMock.mockReturnValue({ test: vi.fn(), testing: false });
useConnectionTesterMock.mockReturnValue({ test: vi.fn(), isTesting: false });
});

it('deve permitir focar e navegar nos botões de ação via teclado', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ vi.mock('@/hooks/intelligence', () => ({
}));

describe('ConnectionsOverviewTable Regression Tests', () => {
const useAuthMock = vi.mocked(useAuth);
const useConnectionsOverviewMock = vi.mocked(useConnectionsOverview);
const useConnectionTesterMock = vi.mocked(useConnectionTester);
const useConsecutiveFailuresMock = vi.mocked(useConsecutiveFailures);
const useSecretsManagerMock = vi.mocked(useSecretsManager);
const useAuthMock = vi.mocked(useAuth) as unknown as ReturnType<typeof vi.fn>;
const useConnectionsOverviewMock = vi.mocked(useConnectionsOverview) as unknown as ReturnType<
typeof vi.fn
>;
const useConnectionTesterMock = vi.mocked(useConnectionTester) as unknown as ReturnType<
typeof vi.fn
>;
const useConsecutiveFailuresMock = vi.mocked(useConsecutiveFailures) as unknown as ReturnType<
typeof vi.fn
>;
const useSecretsManagerMock = vi.mocked(useSecretsManager) as unknown as ReturnType<typeof vi.fn>;
Comment on lines +40 to +50

const mockRows = [
{
Expand Down Expand Up @@ -84,7 +90,7 @@ describe('ConnectionsOverviewTable Regression Tests', () => {
});
useConnectionTesterMock.mockReturnValue({
test: vi.fn(),
testing: false,
isTesting: false,
});
useConsecutiveFailuresMock.mockReturnValue({
map: new Map(),
Expand Down
199 changes: 119 additions & 80 deletions src/components/inventory/SupplierRiskPanel.tsx

Large diffs are not rendered by default.

95 changes: 48 additions & 47 deletions src/components/layout/sidebar/RestrictedRouteNotice.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import { ShieldAlert, KeyRound, Lock } from "lucide-react";
import { useLocation, Link } from "react-router-dom";
import { useAuth } from "@/contexts/AuthContext";
import {
isDevOnlyPath,
isAdminOnlyPath,
} from "@/lib/navigation/restricted-routes";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { ShieldAlert, KeyRound, Lock } from 'lucide-react';
import { useLocation, Link } from 'react-router-dom';
import { useAuth } from '@/contexts/AuthContext';
import { isDevOnlyPath, isAdminOnlyPath } from '@/lib/navigation/restricted-routes';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';

interface RestrictedRouteNoticeProps {
isCollapsed: boolean;
Expand All @@ -27,9 +19,7 @@ interface RestrictedRouteNoticeProps {
* - No modo colapsado, vira só o ícone com tooltip explicativo.
* - Dev nunca vê (tem acesso).
*/
export function RestrictedRouteNotice({
isCollapsed,
}: RestrictedRouteNoticeProps) {
export function RestrictedRouteNotice({ isCollapsed }: RestrictedRouteNoticeProps) {
const location = useLocation();
const { isAdmin, isDev, rolesLoaded } = useAuth();
const path = location.pathname;
Expand All @@ -42,16 +32,15 @@ export function RestrictedRouteNotice({

// Rota técnica: precisa de dev. Bloqueia tanto vendedor quanto admin.
// Rota admin: bloqueia só vendedor.
const blocked =
(isDevRoute && !isDev) || (isAdminRoute && !isAdmin && !isDev);
const blocked = (isDevRoute && !isDev) || (isAdminRoute && !isAdmin && !isDev);
if (!blocked) return null;

const requiredRole = isDevRoute ? "dev" : "admin";
const title = "Acesso Restrito";
const requiredRole = isDevRoute ? 'dev' : 'admin';
const title = 'Acesso Restrito';
const description = isDevRoute
? "Esta funcionalidade é exclusiva para a equipe técnica de engenharia."
: "Esta funcionalidade exige permissões de supervisão ou administração.";
? 'Esta funcionalidade é exclusiva para a equipe técnica de engenharia.'
: 'Esta funcionalidade exige permissões de supervisão ou administração.';

const icon = isDevRoute ? KeyRound : Lock;
const Icon = icon;

Expand All @@ -64,27 +53,36 @@ export function RestrictedRouteNotice({
role="status"
aria-label={`${title}: ${description}`}
className={cn(
"mx-auto my-2 flex h-8 w-8 items-center justify-center rounded-md",
"bg-amber-500/10 text-amber-500 border border-amber-500/30 transition-all duration-300",
"hover:bg-amber-500/20 hover:border-amber-500/50"
'mx-auto my-2 flex h-8 w-8 items-center justify-center rounded-md',
'border border-amber-500/30 bg-amber-500/10 text-amber-500 transition-all duration-300',
'hover:border-amber-500/50 hover:bg-amber-500/20',
)}
>
<Icon className="h-4 w-4" aria-hidden="true" />
</div>
</TooltipTrigger>
<TooltipContent side="right" className="max-w-xs border-amber-500/20 bg-background/95 backdrop-blur-md">
<p className="font-bold text-amber-500 text-xs flex items-center gap-1.5">
<TooltipContent
side="right"
className="max-w-xs border-amber-500/20 bg-background/95 backdrop-blur-md"
>
<p className="flex items-center gap-1.5 text-xs font-bold text-amber-500">
<ShieldAlert className="h-3 w-3" />
{title}
</p>
<p className="text-[11px] mt-1 text-muted-foreground leading-relaxed">
{description}
</p>
<div className="mt-2 pt-2 border-t border-border/40 flex items-center justify-between gap-4">
<p className="mt-1 text-[11px] leading-relaxed text-muted-foreground">{description}</p>
<div className="mt-2 flex items-center justify-between gap-4 border-t border-border/40 pt-2">
<span className="text-[10px] text-muted-foreground">
Nível: <span className="font-mono font-bold text-amber-600/80 uppercase">{requiredRole}</span>
Nível:{' '}
<span className="font-mono font-bold uppercase text-amber-600/80">
{requiredRole}
</span>
</span>
<Button asChild size="xs" variant="ghost" className="h-6 text-[10px] px-2 hover:bg-amber-500/10 hover:text-amber-600">
<Button
asChild
size="sm"
variant="ghost"
className="h-6 px-2 text-[10px] hover:bg-amber-500/10 hover:text-amber-600"
>
<Link to="/">Sair</Link>
</Button>
</div>
Expand All @@ -105,23 +103,27 @@ export function RestrictedRouteNotice({
<div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-lg bg-amber-500/20 text-amber-500 shadow-inner">
<Icon className="h-4 w-4" aria-hidden="true" />
</div>
<div className="flex-1 min-w-0">
<div className="min-w-0 flex-1">
<div className="flex items-center justify-between gap-2">
<p className="font-bold text-amber-500 text-[11px] uppercase tracking-wider">
{title}
</p>
<span className="rounded bg-amber-500/20 px-1.5 py-0.5 font-mono text-[9px] font-bold text-amber-600 uppercase">
<p className="text-[11px] font-bold uppercase tracking-wider text-amber-500">{title}</p>
<span className="rounded bg-amber-500/20 px-1.5 py-0.5 font-mono text-[9px] font-bold uppercase text-amber-600">
{requiredRole}
</span>
</div>
<p className="text-muted-foreground mt-1 text-[11px] leading-relaxed">
{description}
</p>
<p className="mt-1 text-[11px] leading-relaxed text-muted-foreground">{description}</p>
<div className="mt-2.5 flex items-center gap-2">
<Button asChild size="xs" className="h-7 px-3 bg-amber-500 hover:bg-amber-600 text-white font-bold text-[10px] rounded-lg transition-all duration-300">
<Button
asChild
size="sm"
className="h-7 rounded-lg bg-amber-500 px-3 text-[10px] font-bold text-white transition-all duration-300 hover:bg-amber-600"
>
<Link to="/">Voltar ao Início</Link>
</Button>
<Button variant="ghost" size="xs" className="h-7 px-2 text-[10px] text-muted-foreground hover:text-foreground">
<Button
variant="ghost"
size="sm"
className="h-7 px-2 text-[10px] text-muted-foreground hover:text-foreground"
>
Solicitar Acesso
</Button>
</div>
Expand All @@ -130,4 +132,3 @@ export function RestrictedRouteNotice({
</div>
);
}

2 changes: 1 addition & 1 deletion src/hooks/products/useStockAlerts.integration.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ describe('useStockAlerts integration', () => {
await waitFor(() => expect(result.current.isSuccess).toBe(true));

const callArgs = invokeExternalDbMock.mock.calls[0][0];
const selectStr = callArgs.select;
const selectStr = callArgs.select ?? '';

const fields = selectStr.split(',').map((f: string) => f.trim());
expect(fields).not.toContain('supplier_name');
Expand Down
21 changes: 12 additions & 9 deletions src/lib/personalization/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,27 +34,28 @@ export function selectBestTable(

// Filtrar por nome da técnica
if (criteria.techniqueName) {
const byName = candidates.filter((t) =>
t.techniqueName.toLowerCase().includes(criteria.techniqueName.toLowerCase()),
);
const techniqueName = criteria.techniqueName.toLowerCase();
const byName = candidates.filter((t) => t.techniqueName.toLowerCase().includes(techniqueName));
if (byName.length > 0) candidates = byName;
}

// Filtrar por código da técnica
if (criteria.techniqueCode) {
const techniqueCode = criteria.techniqueCode.toLowerCase();
const byCode = candidates.filter(
(t) =>
t.tableCode.toLowerCase().includes(criteria.techniqueCode.toLowerCase()) ||
criteria.techniqueCode.toLowerCase().includes(t.tableCode.toLowerCase()),
t.tableCode.toLowerCase().includes(techniqueCode) ||
techniqueCode.includes(t.tableCode.toLowerCase()),
);
if (byCode.length > 0) candidates = byCode;
}

// Ordenar por número de cores (preferir a que atende exatamente)
if (criteria.colors) {
const colors = criteria.colors;
candidates.sort((a, b) => {
const aFits = a.maxColors !== null && a.maxColors >= criteria.colors;
const bFits = b.maxColors !== null && b.maxColors >= criteria.colors;
const aFits = a.maxColors !== null && a.maxColors >= colors;
const bFits = b.maxColors !== null && b.maxColors >= colors;

if (aFits && !bFits) return -1;
if (!aFits && bFits) return 1;
Expand All @@ -71,10 +72,12 @@ export function selectBestTable(

// Filtrar por dimensões
if (criteria.widthCm && criteria.heightCm) {
const widthCm = criteria.widthCm;
const heightCm = criteria.heightCm;
const byDimensions = candidates.filter(
(t) =>
(t.maxWidthCm === null || t.maxWidthCm >= criteria.widthCm) &&
(t.maxHeightCm === null || t.maxHeightCm >= criteria.heightCm),
(t.maxWidthCm === null || t.maxWidthCm >= widthCm) &&
(t.maxHeightCm === null || t.maxHeightCm >= heightCm),
);
if (byDimensions.length > 0) candidates = byDimensions;
}
Expand Down
Loading
Loading