From 82834f88b03dd05c87a2355a35942eec2f0827d1 Mon Sep 17 00:00:00 2001 From: nicktrn <55853254+nicktrn@users.noreply.github.com> Date: Wed, 17 Jun 2026 18:46:27 +0100 Subject: [PATCH] fix(webapp): admin feature flag number inputs and scrolling --- .../components/admin/FeatureFlagsDialog.tsx | 15 ++++++++ .../app/components/admin/FlagControls.tsx | 35 +++++++++++++++++++ .../webapp/app/routes/admin.feature-flags.tsx | 24 ++++++++++++- apps/webapp/app/routes/admin.tsx | 8 +++-- apps/webapp/app/v3/featureFlags.ts | 10 ++++++ 5 files changed, 89 insertions(+), 3 deletions(-) diff --git a/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx b/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx index df8669d36dd..b1050e60f78 100644 --- a/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx +++ b/apps/webapp/app/components/admin/FeatureFlagsDialog.tsx @@ -18,6 +18,7 @@ import { UNSET_VALUE, BooleanControl, EnumControl, + NumberControl, StringControl, WorkerGroupControl, type WorkerGroup, @@ -242,6 +243,20 @@ export function FeatureFlagsDialog({ }} dimmed={!isOverridden} /> + ) : control.type === "number" ? ( + { + if (val === undefined) { + unsetFlag(key); + } else { + setFlagValue(key, val); + } + }} + dimmed={!isOverridden} + /> ) : control.type === "string" ? ( void; + min?: number; + max?: number; + dimmed: boolean; +}) { + // Number and string fields share the same input shape; surface the range + // (or "number") as the placeholder so an unset field still signals its type. + const placeholder = min !== undefined && max !== undefined ? `${min}-${max}` : "number"; + return ( + { + const next = e.target.valueAsNumber; + onChange(Number.isNaN(next) ? undefined : next); + }} + placeholder={placeholder} + className={cn("w-40", dimmed && "opacity-50")} + /> + ); +} + export function StringControl({ value, onChange, diff --git a/apps/webapp/app/routes/admin.feature-flags.tsx b/apps/webapp/app/routes/admin.feature-flags.tsx index 02faa7add91..71a645a88ed 100644 --- a/apps/webapp/app/routes/admin.feature-flags.tsx +++ b/apps/webapp/app/routes/admin.feature-flags.tsx @@ -35,6 +35,7 @@ import { UNSET_VALUE, BooleanControl, EnumControl, + NumberControl, StringControl, WorkerGroupControl, type WorkerGroup, @@ -352,6 +353,22 @@ export default function AdminFeatureFlagsRoute() { /> )} + {control.type === "number" && ( + { + if (val === undefined) { + unsetFlag(key); + } else { + setFlagValue(key, val); + } + }} + dimmed={!isSet} + /> + )} + {control.type === "string" && ( ); @@ -467,6 +485,7 @@ function ConfirmDialog({ lockedKeys, onConfirm, isSaving, + saveError, }: { open: boolean; onOpenChange: (open: boolean) => void; @@ -476,6 +495,7 @@ function ConfirmDialog({ lockedKeys: readonly string[]; onConfirm: () => void; isSaving: boolean; + saveError: string | null; }) { const editableKeys = Object.keys(controlTypes) .filter((key) => !lockedKeys.includes(key)) @@ -519,7 +539,7 @@ function ConfirmDialog({ These changes affect all organizations globally. Please review carefully. -
+
{changes.length === 0 ? (

No changes to apply.

) : ( @@ -546,6 +566,8 @@ function ConfirmDialog({ )}
+ {saveError && {saveError}} +