From f7331f15a25dae7312f920139422f54ab0dd3fab Mon Sep 17 00:00:00 2001 From: catalyst17 Date: Wed, 28 May 2025 21:48:47 +0000 Subject: [PATCH] feat: enhance aggregate parameter input with multi-select presets (#7168) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## [Dashboard] Feature: Enhance Aggregate Parameter Input with Multi-Select Functionality ## Notes for the reviewer This PR replaces the simple dropdown select with a more robust multi-select component for aggregate parameter inputs. The new implementation allows users to select multiple presets and displays them as badges. ## How to test Test the new aggregate parameter input by: 1. Opening the insight blueprint page 2. Selecting multiple presets from the dropdown 3. Verifying that selected values appear as badges 4. Testing the search functionality within the preset selector 5. Confirming that manual input still works alongside preset selection ## Summary by CodeRabbit - **New Features** - Enhanced aggregate parameter input with combined manual entry and multi-select for presets. - Added search functionality within the multi-select component for easier preset selection. - Updated parameter descriptions and examples for "aggregate" to clarify multi-selection usage. - **Refactor** - Made input options optional and improved synchronization between manual input and multi-select. - Adjusted tooltip positioning for better UI alignment on aggregate parameters. --- ## PR-Codex overview This PR enhances the `ParameterSection` and `AggregateParameterInput` components to provide dynamic descriptions and examples based on the parameter type. It also refines the handling of selected values and manual input for aggregations, replacing the `Select` component with a `MultiSelect`. ### Detailed summary - Updated `description` and `exampleToShow` in `ParameterSection` based on `param.name`. - Introduced `MultiSelect` in `AggregateParameterInput` for selecting aggregation presets. - Added state management for manual input and selected values. - Removed the `Select` component in favor of a more flexible input system. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` --- .../aggregate-parameter-input.client.tsx | 167 +++++++++++++----- .../blueprint-playground.client.tsx | 13 +- 2 files changed, 133 insertions(+), 47 deletions(-) diff --git a/apps/playground-web/src/app/insight/[blueprint_slug]/aggregate-parameter-input.client.tsx b/apps/playground-web/src/app/insight/[blueprint_slug]/aggregate-parameter-input.client.tsx index b60637b8819..536e585cef6 100644 --- a/apps/playground-web/src/app/insight/[blueprint_slug]/aggregate-parameter-input.client.tsx +++ b/apps/playground-web/src/app/insight/[blueprint_slug]/aggregate-parameter-input.client.tsx @@ -1,14 +1,9 @@ "use client"; +import { MultiSelect } from "@/components/blocks/multi-select"; import { Input } from "@/components/ui/input"; -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select"; import { cn } from "@/lib/utils"; +import { useCallback, useEffect, useMemo, useState } from "react"; import type { ControllerRenderProps } from "react-hook-form"; interface Preset { @@ -145,53 +140,137 @@ interface AggregateParameterInputProps { }, string >; - showTip: boolean; - hasError: boolean; - placeholder: string; - endpointPath: string; // New prop + showTip?: boolean; + hasError?: boolean; + placeholder?: string; + endpointPath: string; } export function AggregateParameterInput(props: AggregateParameterInputProps) { - const { field, showTip, hasError, placeholder, endpointPath } = props; + const { field, placeholder, endpointPath, showTip } = props; const { value, onChange } = field; - const presets = getAggregatePresets(endpointPath); + const presets = useMemo( + () => getAggregatePresets(endpointPath), + [endpointPath], + ); + + const selectedValues = useMemo(() => { + if (!value) return []; + return Array.from( + new Set( + String(value) + .split(",") + .map((v) => v.trim()) // remove leading / trailing spaces + .filter(Boolean), + ), + ); + }, [value]); + + const handlePresetChange = useCallback( + (values: string[]) => { + onChange({ target: { value: values.join(",") } }); + }, + [onChange], + ); + + // Custom search function for the MultiSelect + const searchFunction = useCallback( + (option: { value: string; label: string }, searchTerm: string) => { + if (!searchTerm) return true; + const query = searchTerm.toLowerCase(); + return ( + option.label.toLowerCase().includes(query) || + option.value.toLowerCase().includes(query) + ); + }, + [], + ); + + // Get display values for the selected items + useCallback( + (value: string) => { + const preset = presets.find((p) => p.value === value); + return preset ? preset.label : value; + }, + [presets], + ); + + // Format selected values for display in the MultiSelect + useMemo(() => { + return selectedValues.map((value) => { + const preset = presets.find((p) => p.value === value); + return { + label: preset?.label || value, + value, + }; + }); + }, [selectedValues, presets]); + + // State for the manual input text + const [manualInput, setManualInput] = useState(""); + + // Update manual input when selected values change + useEffect(() => { + if (selectedValues.length === 0) { + setManualInput(""); + } else { + setManualInput(selectedValues.join(", ")); + } + }, [selectedValues]); + + // Handle manual input changes + const handleManualInputChange = (e: React.ChangeEvent) => { + const value = e.target.value; + setManualInput(value); + + // Update selected values by splitting on commas and trimming whitespace + const newValues = value + .split(",") + .map((v) => v.trim()) + .filter(Boolean); + + onChange({ target: { value: newValues.join(",") } }); + }; return ( -
- + {/* Editable formula text field */} +
+ +
+ + {/* MultiSelect for choosing aggregations */} + ( +
+ {option.label} + + {option.value} + +
)} - placeholder={placeholder} /> -
); } diff --git a/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx b/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx index 46c60c6759e..ec239e54d86 100644 --- a/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx +++ b/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx @@ -527,7 +527,9 @@ function ParameterSection(props: {
{description && (

- {description} + {param.name === "aggregate" + ? "Aggregation(s). You can type in multiple, separated by a comma, or select from the presets" + : description}

)} @@ -536,7 +538,9 @@ function ParameterSection(props: {

Example:{" "} - {exampleToShow} + {param.name === "aggregate" + ? "count() AS count_all, countDistinct(address) AS unique_addresses" + : exampleToShow}

@@ -547,7 +551,10 @@ function ParameterSection(props: {