feat(ui): ocultar dados sensíveis na tabela
- adiciona botão para alternar visibilidade de IP, porta, usuário e senha - mantém placeholders quando oculto e preserva layout paginadomaster
parent
7460577423
commit
c665aa18ea
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { useState } from "react";
|
||||||
import type { Server } from "../types/Server";
|
import type { Server } from "../types/Server";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -25,12 +26,24 @@ export const ServersTable = ({
|
||||||
onPageChange,
|
onPageChange,
|
||||||
onPageSizeChange,
|
onPageSizeChange,
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
|
const [hideSensitive, setHideSensitive] = useState(false);
|
||||||
const showingFrom = totalItems === 0 ? 0 : page * pageSize + 1;
|
const showingFrom = totalItems === 0 ? 0 : page * pageSize + 1;
|
||||||
const showingTo = totalItems === 0 ? 0 : Math.min((page + 1) * pageSize, totalItems);
|
const showingTo = totalItems === 0 ? 0 : Math.min((page + 1) * pageSize, totalItems);
|
||||||
const hasResults = servers.length > 0;
|
const hasResults = servers.length > 0;
|
||||||
|
|
||||||
|
const formatSensitiveValue = (value: string | number) => (hideSensitive ? "••••" : value);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={Styles.card}>
|
<div className={Styles.card}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={Styles.hideButton}
|
||||||
|
onClick={() => setHideSensitive((prev) => !prev)}
|
||||||
|
disabled={loading || (!hasResults && !error)}
|
||||||
|
aria-pressed={hideSensitive}
|
||||||
|
>
|
||||||
|
{hideSensitive ? "Mostrar dados sensíveis" : "Ocultar dados sensíveis"}
|
||||||
|
</button>
|
||||||
{loading && <div className={Styles.status}>Carregando servidores...</div>}
|
{loading && <div className={Styles.status}>Carregando servidores...</div>}
|
||||||
{error && <div className={Styles.error}>{error}</div>}
|
{error && <div className={Styles.error}>{error}</div>}
|
||||||
{!loading && !error && servers.length === 0 && (
|
{!loading && !error && servers.length === 0 && (
|
||||||
|
|
@ -59,11 +72,13 @@ export const ServersTable = ({
|
||||||
className="hover:bg-gray-50 transition-colors even:bg-gray-50/50"
|
className="hover:bg-gray-50 transition-colors even:bg-gray-50/50"
|
||||||
>
|
>
|
||||||
<td className={Styles.rowCell}>{server.name}</td>
|
<td className={Styles.rowCell}>{server.name}</td>
|
||||||
<td className={Styles.rowCell}>{server.ip}</td>
|
<td className={Styles.rowCell}>{formatSensitiveValue(server.ip)}</td>
|
||||||
<td className={Styles.rowCell}>{server.port}</td>
|
<td className={Styles.rowCell}>{formatSensitiveValue(server.port)}</td>
|
||||||
<td className={Styles.rowCell}>{server.user}</td>
|
<td className={Styles.rowCell}>{formatSensitiveValue(server.user)}</td>
|
||||||
<td className={Styles.rowCell}>
|
<td className={Styles.rowCell}>
|
||||||
<code className="text-xs bg-gray-100 px-2 py-1 rounded">{server.password}</code>
|
<code className="text-xs bg-gray-100 px-2 py-1 rounded">
|
||||||
|
{hideSensitive ? "••••" : server.password}
|
||||||
|
</code>
|
||||||
</td>
|
</td>
|
||||||
<td className={`${Styles.rowCell} capitalize`}>{server.type.toLowerCase()}</td>
|
<td className={`${Styles.rowCell} capitalize`}>{server.type.toLowerCase()}</td>
|
||||||
<td className={`${Styles.rowCell} capitalize`}>{server.application.toLowerCase()}</td>
|
<td className={`${Styles.rowCell} capitalize`}>{server.application.toLowerCase()}</td>
|
||||||
|
|
@ -122,7 +137,7 @@ export const ServersTable = ({
|
||||||
};
|
};
|
||||||
|
|
||||||
const Styles = {
|
const Styles = {
|
||||||
card: "bg-card border border-cardBorder shadow-sm rounded-lg overflow-hidden",
|
card: "relative bg-card border border-cardBorder shadow-sm rounded-lg overflow-hidden",
|
||||||
status: "p-4 text-text-secondary text-sm",
|
status: "p-4 text-text-secondary text-sm",
|
||||||
error: "p-4 text-red-600 text-sm",
|
error: "p-4 text-red-600 text-sm",
|
||||||
tableWrapper: "overflow-x-auto rounded-lg shadow-sm border border-cardBorder",
|
tableWrapper: "overflow-x-auto rounded-lg shadow-sm border border-cardBorder",
|
||||||
|
|
@ -139,4 +154,5 @@ const Styles = {
|
||||||
pageButtons: "flex items-center gap-3",
|
pageButtons: "flex items-center gap-3",
|
||||||
pageButton: "rounded-md border border-cardBorder px-3 py-1.5 text-sm font-medium text-text hover:bg-bg disabled:opacity-50 disabled:hover:bg-transparent",
|
pageButton: "rounded-md border border-cardBorder px-3 py-1.5 text-sm font-medium text-text hover:bg-bg disabled:opacity-50 disabled:hover:bg-transparent",
|
||||||
pageIndicator: "text-sm text-text-secondary",
|
pageIndicator: "text-sm text-text-secondary",
|
||||||
|
hideButton: "absolute right-3 top-3 rounded-md border border-cardBorder px-3 py-1.5 text-xs font-semibold uppercase tracking-wide text-text-secondary hover:bg-bg disabled:opacity-50 disabled:hover:bg-transparent bg-white shadow-sm",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue