Files
OmniRoute/src/shared/components/ColumnToggle.tsx
nguyenha935 4012bac41d fix(i18n): preserve remaining Vietnamese localization (#7935)
* fix(i18n): preserve remaining Vietnamese localization

* chore(quality): rebaseline file-size cap for 9 dashboard components (i18n wiring)

Restoring the Vietnamese localization on 9 dashboard components (useTranslations
wiring + t()/tc() call-site swaps for previously hardcoded strings) grows each
file by a small, irreducible amount. Bumps the frozen file-size-baseline.json
caps to match, with a justification entry per the project's own ratchet policy.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* fix(i18n): wire weekday localization + add missing qwen CLI description

Two gaps left by this PR's own new contract tests, caught while
reconciling the branch against the release tip:

- CostOverviewTab.tsx added formatWeekdayLabel() but never called it;
  the Weekly Usage Pattern chart still showed raw English day
  abbreviations regardless of locale. Now maps weeklyPattern rows
  through it before handing them to WeeklyPatternCard.
- cliTools.toolDescriptions was missing an entry for "qwen" (a
  baseUrlSupport:"full" tool) in both en.json and vi.json, failing
  the PR's own cli-catalog-display-contract.test.ts.

Covered by the PR's existing tests/unit/dashboard-localization-contract.test.ts
and tests/unit/cli-catalog-display-contract.test.ts (both now pass).

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* i18n(vi): backfill the 4 proxySubscription keys #7299 added to en.json

#7299 (proxy subscriptions) merged while this branch was rebasing, adding
settings.proxySubscriptionsTab and settings.proxySubscription.error.{LOCAL_CORE_ENDPOINT_INVALID,
NEEDS_CORE_NOT_CONFIGURED,NO_USABLE_NODES} to en.json. This PR's own
i18n-vi-completeness contract asserts full en↔vi key parity, so the merge of the
current release tip surfaced them as missing. Adds the Vietnamese translations,
keeping the SS/VMess/Trojan/VLESS/SOCKS5 technical terms verbatim.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: nguyenha935 <208228297+nguyenha935@users.noreply.github.com>
Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Co-authored-by: nguyenha935 <nguyenha935@users.noreply.github.com>
2026-07-21 13:41:02 -03:00

103 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
/**
* ColumnToggle — Shared UI primitive (T-29)
*
* Dropdown menu for toggling table column visibility.
* Used by RequestLoggerV2, ProxyLogger, etc.
*
* Usage:
* <ColumnToggle
* columns={[{ key: 'model', label: 'Model' }, ...]}
* visible={{ model: true, provider: false, ... }}
* onToggle={(key) => setVisible({...visible, [key]: !visible[key]})}
* />
*/
import { useState, useRef, useEffect } from "react";
import { useTranslations } from "next-intl";
export default function ColumnToggle({ columns = [], visible = {}, onToggle }) {
const t = useTranslations("common");
const [open, setOpen] = useState(false);
const ref = useRef(null);
// Close on outside click
useEffect(() => {
if (!open) return;
const handler = (e) => {
if (ref.current && !ref.current.contains(e.target)) setOpen(false);
};
document.addEventListener("mousedown", handler);
return () => document.removeEventListener("mousedown", handler);
}, [open]);
return (
<div ref={ref} style={{ position: "relative" }}>
<button
onClick={() => setOpen(!open)}
title={t("toggleColumns")}
style={{
padding: "6px 10px",
borderRadius: "6px",
border: "1px solid rgba(255,255,255,0.1)",
background: "rgba(255,255,255,0.05)",
color: "var(--text-secondary, #888)",
fontSize: "13px",
cursor: "pointer",
display: "flex",
alignItems: "center",
gap: "4px",
}}
>
<span style={{ fontSize: "14px" }}></span>
{t("columns")}
</button>
{open && (
<div
style={{
position: "absolute",
top: "100%",
right: 0,
marginTop: "4px",
background: "rgba(20,20,30,0.95)",
border: "1px solid rgba(255,255,255,0.1)",
borderRadius: "8px",
padding: "8px",
zIndex: 50,
minWidth: "160px",
backdropFilter: "blur(12px)",
}}
>
{columns.map((col) => (
<label
key={col.key}
style={{
display: "flex",
alignItems: "center",
gap: "8px",
padding: "4px 8px",
cursor: "pointer",
fontSize: "12px",
color: visible[col.key]
? "var(--text-primary, #e0e0e0)"
: "var(--text-secondary, #888)",
borderRadius: "4px",
}}
>
<input
type="checkbox"
checked={visible[col.key] ?? true}
onChange={() => onToggle(col.key)}
style={{ accentColor: "#6366f1" }}
/>
{col.label}
</label>
))}
</div>
)}
</div>
);
}