refactor: now using MyQueryBuilder (temp name) in Data Explorer pg as it implements zustand state management to aid the transition from retriggering an api call on every new filter added

This commit is contained in:
2026-11-12 09:59:00 -08:00
parent 39ee717a6c
commit 34a2501e5e
5 changed files with 577 additions and 102 deletions
+95 -38
View File
@@ -1,8 +1,24 @@
import React, { useRef } from "react";
import { Button, Stack, Flex, Field, NativeSelect, Input, HoverCard, Text, NumberInput, Box } from "@chakra-ui/react";
import {
Button,
Stack,
Flex,
Field,
NativeSelect,
Input,
HoverCard,
Text,
NumberInput,
Box,
useSlotRecipe,
Combobox,
Portal,
useFilter,
useListCollection
} from "@chakra-ui/react";
import { Plus, CircleMinus, Files, ClipboardPaste, Trash } from 'lucide-react';
// import { GrAdd, GrSubtractCircle } from "react-icons/gr";
// import { FaCopy, FaPaste, FaTrash } from "react-icons/fa";
import { useState } from 'react';
import useDataFilterStore from '../../store/useDataFilterStore.jsx';
// ============================================================================
// 1. FILTER ROW (The individual criteria inputs)
@@ -80,7 +96,7 @@ const FilterRow = React.memo(({ filter, columns, setUrl, bundleId, copiedFilter
</Button>
</HoverCard.Trigger>
<HoverCard.Positioner>
<HoverCard.Content p="2" bg="widgetItemExpandedBg"><Text fontSize="sm">Remove Filter</Text></HoverCard.Content>
<HoverCard.Content p="2" bg="white"><Text fontSize="sm">Remove Filter</Text></HoverCard.Content>
</HoverCard.Positioner>
</HoverCard.Root>
@@ -92,7 +108,7 @@ const FilterRow = React.memo(({ filter, columns, setUrl, bundleId, copiedFilter
</Button>
</HoverCard.Trigger>
<HoverCard.Positioner>
<HoverCard.Content p="2" bg="widgetItemExpandedBg"><Text fontSize="sm">Copy Filter</Text></HoverCard.Content>
<HoverCard.Content p="2" bg="white"><Text fontSize="sm">Copy Filter</Text></HoverCard.Content>
</HoverCard.Positioner>
</HoverCard.Root>
@@ -124,7 +140,7 @@ const FilterRow = React.memo(({ filter, columns, setUrl, bundleId, copiedFilter
</Button>
</HoverCard.Trigger>
<HoverCard.Positioner>
<HoverCard.Content p="2" bg="widgetItemExpandedBg"><Text fontSize="sm">Paste Filter</Text></HoverCard.Content>
<HoverCard.Content p="2" bg="white"><Text fontSize="sm">Paste Filter</Text></HoverCard.Content>
</HoverCard.Positioner>
</HoverCard.Root>
@@ -207,6 +223,8 @@ const FilterBundle = ({ bundle, columns, url, setUrl, copiedFilter }) => {
}) : (b)
),
}));
};
return (
@@ -234,8 +252,25 @@ const FilterBundle = ({ bundle, columns, url, setUrl, copiedFilter }) => {
// 3. MAIN QUERY BUILDER (The Engine Wrapper)
// ============================================================================
export default function QueryBuilder({ url, setUrl, allColumns, getColumns, pullTable, isLoading, isReadyRef }) {
const copiedFilter = useRef(null);
// STYLING
const dataExplorerRecipe = useSlotRecipe({ key: "dataExplorer" });
const dataExplorerStyle = dataExplorerRecipe();
// SELECT DROPDOWN MENU
const { contains } = useFilter({ sensitivity: "base" })
const { collection, filter } = useListCollection({
initialItems: tables,
filter: contains,
})
// STATE MANAGEMENT
const copiedFilter = useRef(null);
const [value, setValue] = useState([]);
const addNewGroup = useDataFilterStore(state => state.addNewGroup);
const filterGroups = useDataFilterStore(state => state.filterGroups);
// FUNCTIONS
const handleAddBundle = () => {
setUrl(prev => ({
...prev,
@@ -253,39 +288,56 @@ export default function QueryBuilder({ url, setUrl, allColumns, getColumns, pull
},
],
}));
// adding zustand state management as a test here
addNewGroup();
};
console.log("filter groups", filterGroups);
return (
<Flex direction="column" gap="4" w="100%" p="4" bg="transparent">
<Flex direction="column" gap={2} w="100%" bg="transparent" css={dataExplorerStyle.query_builder}>
{/* Top Controls: Source & Execute */}
<Flex gap="4" align="flex-end">
<Field.Root maxW="300px">
<Field.Label color="text">Data Source</Field.Label>
<NativeSelect.Root>
<NativeSelect.Field
bg="widgetItemBg"
color="text"
value={url.source || ""}
onChange={(e) => {
const selectedView = e.target.value;
setUrl(prev => ({ ...prev, source: selectedView }));
// 🚨 FIXED: Now uses relative pathing for the production API
const endpoint = "/api/v3/view_dash_event_search_columns";
getColumns(endpoint);
}}
>
<option value="" disabled hidden>Select View</option>
<option value="main">Main View</option>
{/*<option value="test">Test View</option>*/}
</NativeSelect.Field>
<NativeSelect.Indicator />
</NativeSelect.Root>
</Field.Root>
<Flex gap={2} align="flex-end">
<Combobox.Root
collection={collection}
onInputValueChange={(e) => filter(e.inputValue)}
value={value}
onValueChange={(e) => {
setValue(e.value);
const selectedView = e.value;
setUrl(prev => ({ ...prev, source: selectedView }));
// need to get all columns as default in param building
const endpoint = "/api/v3/view_dash_event_search_columns";
getColumns(endpoint);
}}
width="320px"
>
<Combobox.Label>Select Table</Combobox.Label>
<Combobox.Control>
<Combobox.Input placeholder="Type to search" />
<Combobox.IndicatorGroup>
<Combobox.ClearTrigger />
<Combobox.Trigger />
</Combobox.IndicatorGroup>
</Combobox.Control>
<Portal>
<Combobox.Positioner>
<Combobox.Content>
<Combobox.Empty>No items found</Combobox.Empty>
{collection.items.map((item) => (
<Combobox.Item item={item} key={item.value}>
{item.label}
<Combobox.ItemIndicator />
</Combobox.Item>
))}
</Combobox.Content>
</Combobox.Positioner>
</Portal>
</Combobox.Root>
{/*</Field.Root>*/}
<Button
bg="blue.600"
color="white"
_hover={{ bg: "blue.500" }}
loading={isLoading}
onClick={() => {
isReadyRef.current = true;
@@ -298,11 +350,11 @@ export default function QueryBuilder({ url, setUrl, allColumns, getColumns, pull
{/* Filter Builder Engine */}
{url.source && allColumns?.types && (
<Stack w="100%" gap="4">
<Text fontSize="lg" fontWeight="bold" color="text">Filters</Text>
<Stack w="100%" gap="2">
<Text fontSize="sm" fontWeight="bold" color="text">Filters</Text>
<Box w="100%" maxH="400px" overflow="auto">
<Stack w="100%" gap="4" pr="4">
<Stack w="100%" gap="2" pr="4">
{url.bundles.map((bundle) => (
<FilterBundle key={bundle.id} bundle={bundle} columns={allColumns.types} url={url} setUrl={setUrl} copiedFilter={copiedFilter} />
))}
@@ -315,4 +367,9 @@ export default function QueryBuilder({ url, setUrl, allColumns, getColumns, pull
)}
</Flex>
);
}
}
// LIST OF TABLES USER CAN EXPLORE
const tables = [
{ label: "Events Table", value: "ViewDashEventSearch" },
]