diff --git a/app/components/report-builder-side-panel.tsx b/app/components/report-builder-side-panel.tsx index 310de25d..aad2223f 100644 --- a/app/components/report-builder-side-panel.tsx +++ b/app/components/report-builder-side-panel.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo, useState } from "react"; -import { Button } from "@carbon/react"; +import { Button, ComboBox, Theme } from "@carbon/react"; import { DeleteOutlined } from "@mui/icons-material"; import { REPORT_WINDOW_PRESETS, @@ -63,6 +63,54 @@ function isExternalCostQuery(query: Report["query"]): query is ExternalCostRepor return query.layer === "externalCost"; } +type GroupingOption = { label: string; value: string }; + +function GroupingComboBox({ + index, + grouping, + onChange, +}: { + index: number; + grouping: string; + onChange: (value: string) => void; +}) { + const presetMatch = ALLOCATION_GROUPING_OPTIONS.find((o) => o.value === grouping); + const selectedItem: GroupingOption = + presetMatch ?? { label: grouping, value: grouping }; + const items: GroupingOption[] = presetMatch + ? ALLOCATION_GROUPING_OPTIONS + : [...ALLOCATION_GROUPING_OPTIONS, selectedItem]; + + return ( + + item?.label ?? ""} + selectedItem={selectedItem} + allowCustomValue + onChange={({ + selectedItem: picked, + inputValue, + }: { + selectedItem?: GroupingOption | null; + inputValue?: string | null; + }) => { + if (picked) { + onChange(picked.value); + return; + } + const typed = (inputValue ?? "").trim(); + if (!typed || typed === grouping) return; + onChange(typed.includes(":") ? typed : `label:${typed}`); + }} + /> + + ); +} + function toFilterOptionsByLayer(layer: ReportLayer) { switch (layer) { case "cloudCost": @@ -414,19 +462,13 @@ export default function ReportBuilderSidePanel({
{groupings.map((grouping, index) => (
- +
+ setGroupingAt(index, value)} + /> +