diff --git a/apps/dashboard/src/components/rule-builder/condition-builder.tsx b/apps/dashboard/src/components/rule-builder/condition-builder.tsx index 24a92e5b1..bb6fc412b 100644 --- a/apps/dashboard/src/components/rule-builder/condition-builder.tsx +++ b/apps/dashboard/src/components/rule-builder/condition-builder.tsx @@ -1,6 +1,7 @@ "use client"; import { Button, cn, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui"; +import { DesignInput, DesignSelectorDropdown } from "@/components/design-components"; import { type ConditionNode, createEmptyCondition, @@ -15,6 +16,13 @@ import { validateCountryCode } from "@stackframe/stack-shared/dist/utils/country import { type ConditionField, type ConditionOperator, conditionFields, fieldMetadata, getOperatorsForField, isNumericField, validateNumericFieldValue } from "@stackframe/stack-shared/dist/utils/cel-fields"; import React from "react"; +const conditionRowSurfaceClass = + "bg-white/90 dark:bg-background/60 shadow-sm ring-1 ring-black/[0.06] dark:ring-white/[0.06]"; +const conditionFieldClass = "h-8 min-w-[120px]"; +const conditionValueClass = "h-8 w-full"; + +const UNSET_SELECT_VALUE = "__unset__"; + /** * Validates whether a string is a valid regular expression. * Returns null if valid, or an error message if invalid. @@ -183,28 +191,24 @@ function ConditionRow({ }; return ( -
- {/* Field selector */} - + onValueChange={(value) => handleFieldChange(value as ConditionField)} + options={FIELD_OPTIONS.map((opt) => ({ value: opt.value, label: opt.label }))} + size="sm" + className={conditionFieldClass} + triggerClassName={conditionFieldClass} + /> - {/* Operator selector */} - + onValueChange={(value) => handleOperatorChange(value as ConditionOperator)} + options={availableOperators.map((op) => ({ value: op, label: OPERATOR_LABELS[op] }))} + size="sm" + className={conditionFieldClass} + triggerClassName={conditionFieldClass} + /> {/* Value input */}
@@ -216,7 +220,7 @@ function ConditionRow({ value={countryCode || null} onChange={(val) => handleCountryCodeListItemChange(index, val ?? "")} className={cn( - "h-8 text-sm flex-1", + conditionValueClass, countryCodeError !== null && "border-destructive ring-1 ring-destructive/30", )} /> @@ -244,19 +248,20 @@ function ConditionRow({
) : condition.operator === 'in_list' ? ( - { const items = e.target.value.split(',').map(s => s.trim()).filter(Boolean); handleValueChange(items); }} placeholder="value1, value2, ... (values cannot contain commas)" className={cn( - "h-8 px-2 text-sm bg-background/60 border rounded-md w-full", + conditionValueClass, countryCodeError !== null ? "border-destructive ring-1 ring-destructive/30" - : "border-border/50", + : undefined, )} /> ) : isCountryCodeField ? ( @@ -264,36 +269,39 @@ function ConditionRow({ value={typeof condition.value === 'string' && condition.value ? condition.value : null} onChange={(val) => handleValueChange(val ?? "")} className={cn( - "h-8 text-sm w-full", + conditionValueClass, countryCodeError !== null && "border-destructive ring-1 ring-destructive/30", )} /> ) : predefinedValues ? ( - + handleValueChange(value === UNSET_SELECT_VALUE ? "" : value)} + options={[ + { value: UNSET_SELECT_VALUE, label: "Select..." }, + ...predefinedValues.map((val) => ({ value: val, label: val })), + ]} + size="sm" + className="w-full" + triggerClassName={conditionValueClass} + /> ) : isNumericField(condition.field) ? ( - handleValueChange(e.target.value === '' ? 0 : Number(e.target.value))} placeholder="0-100" - className="h-8 px-2 text-sm bg-background/60 border border-border/50 rounded-md w-full" + className={conditionValueClass} /> ) : (
- handleValueChange(e.target.value)} placeholder={ @@ -302,10 +310,10 @@ function ConditionRow({ : "Enter value..." } className={cn( - "h-8 px-2 text-sm bg-background/60 border rounded-md flex-1", + conditionValueClass, regexError !== null || countryCodeError !== null ? "border-destructive ring-1 ring-destructive/30" - : "border-border/50" + : undefined, )} /> {(regexError !== null || countryCodeError !== null) && (