From 0461a802d1b504ff3700dd48b8fc51797667c613 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza <8016841+diegosouzapw@users.noreply.github.com> Date: Wed, 20 May 2026 23:47:20 -0300 Subject: [PATCH] feat: Feature Flags Settings Page (Card Grid + DB overrides) (#2457) Integrated into release/v3.8.1 --- node_modules | 1 + .../settings/components/FeatureFlagCard.tsx | 267 ++++---- .../settings/components/FeatureFlagsGrid.tsx | 378 ++++++----- src/app/api/settings/feature-flags/route.ts | 223 ++++--- src/i18n/messages/ar.json | 48 +- src/i18n/messages/az.json | 48 +- src/i18n/messages/bg.json | 48 +- src/i18n/messages/bn.json | 48 +- src/i18n/messages/cs.json | 48 +- src/i18n/messages/da.json | 48 +- src/i18n/messages/de.json | 48 +- src/i18n/messages/en.json | 48 +- src/i18n/messages/es.json | 48 +- src/i18n/messages/fa.json | 48 +- src/i18n/messages/fi.json | 48 +- src/i18n/messages/fr.json | 48 +- src/i18n/messages/gu.json | 48 +- src/i18n/messages/he.json | 48 +- src/i18n/messages/hi.json | 48 +- src/i18n/messages/hu.json | 48 +- src/i18n/messages/id.json | 48 +- src/i18n/messages/in.json | 48 +- src/i18n/messages/it.json | 48 +- src/i18n/messages/ja.json | 48 +- src/i18n/messages/ko.json | 48 +- src/i18n/messages/mr.json | 48 +- src/i18n/messages/ms.json | 48 +- src/i18n/messages/nl.json | 48 +- src/i18n/messages/no.json | 48 +- src/i18n/messages/phi.json | 48 +- src/i18n/messages/pl.json | 48 +- src/i18n/messages/pt-BR.json | 48 +- src/i18n/messages/pt.json | 48 +- src/i18n/messages/ro.json | 48 +- src/i18n/messages/ru.json | 48 +- src/i18n/messages/sk.json | 48 +- src/i18n/messages/sv.json | 48 +- src/i18n/messages/sw.json | 48 +- src/i18n/messages/ta.json | 48 +- src/i18n/messages/te.json | 48 +- src/i18n/messages/th.json | 48 +- src/i18n/messages/tr.json | 48 +- src/i18n/messages/uk-UA.json | 48 +- src/i18n/messages/ur.json | 48 +- src/i18n/messages/vi.json | 48 +- src/i18n/messages/zh-CN.json | 48 +- src/lib/db/featureFlags.ts | 54 +- .../constants/featureFlagDefinitions.ts | 158 ++--- src/shared/utils/featureFlags.ts | 42 +- tests/unit/feature-flags-settings.test.ts | 611 +++++++----------- 50 files changed, 1877 insertions(+), 1873 deletions(-) create mode 120000 node_modules diff --git a/node_modules b/node_modules new file mode 120000 index 0000000000..d6af08994d --- /dev/null +++ b/node_modules @@ -0,0 +1 @@ +/home/diegosouzapw/dev/proxys/OmniRoute/node_modules \ No newline at end of file diff --git a/src/app/(dashboard)/dashboard/settings/components/FeatureFlagCard.tsx b/src/app/(dashboard)/dashboard/settings/components/FeatureFlagCard.tsx index eb364be7d7..58ead505cc 100644 --- a/src/app/(dashboard)/dashboard/settings/components/FeatureFlagCard.tsx +++ b/src/app/(dashboard)/dashboard/settings/components/FeatureFlagCard.tsx @@ -1,5 +1,4 @@ -import React from "react"; -import { AlertTriangle, Loader2, RefreshCw, RotateCcw } from "lucide-react"; +"use client"; interface FeatureFlagCardProps { flag: { @@ -8,7 +7,7 @@ interface FeatureFlagCardProps { description: string; category: "security" | "network" | "policies" | "runtime" | "cli" | "health"; type: "boolean" | "enum"; - enumValues?: string[]; + enumValues?: string[] | null; effectiveValue: string; source: "db" | "env" | "default"; requiresRestart: boolean; @@ -19,167 +18,161 @@ interface FeatureFlagCardProps { saving?: boolean; } -const categoryStyles = { - security: "bg-red-500/15 text-red-500", - network: "bg-blue-500/15 text-blue-500", - policies: "bg-amber-500/15 text-amber-500", - runtime: "bg-purple-500/15 text-purple-500", - cli: "bg-green-500/15 text-green-500", - health: "bg-cyan-500/15 text-cyan-500", +const CATEGORY_STYLES: Record< + FeatureFlagCardProps["flag"]["category"], + { bg: string; text: string; label: string } +> = { + security: { bg: "bg-red-500/15", text: "text-red-400", label: "Security" }, + network: { bg: "bg-blue-500/15", text: "text-blue-400", label: "Network" }, + policies: { bg: "bg-amber-500/15", text: "text-amber-400", label: "Policies" }, + runtime: { bg: "bg-purple-500/15", text: "text-purple-400", label: "Runtime" }, + cli: { bg: "bg-green-500/15", text: "text-green-400", label: "CLI" }, + health: { bg: "bg-cyan-500/15", text: "text-cyan-400", label: "Health" }, }; -const sourceBadgeConfig = { - db: { label: "DB", className: "bg-blue-500/20 text-blue-400" }, - env: { label: "ENV", className: "bg-amber-500/20 text-amber-400" }, - default: { label: "DEF", className: "bg-slate-500/20 text-slate-400" }, +const SOURCE_STYLES: Record< + FeatureFlagCardProps["flag"]["source"], + { bg: string; text: string; label: string } +> = { + db: { bg: "bg-blue-500/20", text: "text-blue-300", label: "DB" }, + env: { bg: "bg-amber-500/20", text: "text-amber-300", label: "ENV" }, + default: { bg: "bg-slate-500/20", text: "text-slate-400", label: "DEF" }, }; -export const FeatureFlagCard: React.FC = ({ - flag, - onToggle, - onReset, - saving = false, -}) => { - const isEnabled = - flag.effectiveValue === "true" || flag.effectiveValue === "1" || flag.effectiveValue === "yes"; +function isEnabled(value: string): boolean { + return value === "true" || value === "1" || value === "yes"; +} - // Base glassmorphism + hover + active states - let cardClass = `feature-flag-card relative flex flex-col justify-between p-4 rounded-xl border bg-black/40 backdrop-blur-md transition-all duration-200 group`; +function Spinner() { + return ( +