diff --git a/studio/components/grid/components/header/filter/FilterPopover.tsx b/studio/components/grid/components/header/filter/FilterPopover.tsx index 2b4c3ac7ea0..1cdecf8f3c3 100644 --- a/studio/components/grid/components/header/filter/FilterPopover.tsx +++ b/studio/components/grid/components/header/filter/FilterPopover.tsx @@ -1,10 +1,14 @@ -import { FC } from 'react' +import { FC, useState, useMemo, useCallback } from 'react' +import { isEqual } from 'lodash' import { Button, IconPlus, IconFilter, Popover } from 'ui' - +import update from 'immutability-helper' import { useUrlState } from 'hooks' + import FilterRow from './FilterRow' import { useTrackedState } from 'components/grid/store' import { formatFilterURLParams } from 'components/grid/SupabaseGrid.utils' +import { Filter } from 'components/grid/types' +import { FilterOperatorOptions } from './Filter.constants' const FilterPopover: FC = () => { const [{ filter: filters }]: any = useUrlState({ arrayKeys: ['filter'] }) @@ -14,7 +18,12 @@ const FilterPopover: FC = () => { : 'Filter' return ( - }> + } + > + ) diff --git a/studio/components/grid/components/header/filter/FilterRow.tsx b/studio/components/grid/components/header/filter/FilterRow.tsx index 6e16d1f8864..6a1a977f427 100644 --- a/studio/components/grid/components/header/filter/FilterRow.tsx +++ b/studio/components/grid/components/header/filter/FilterRow.tsx @@ -1,113 +1,26 @@ -import { debounce } from 'lodash' -import { FC, memo, useState, useEffect, ChangeEvent, useCallback } from 'react' +import { FC, memo } from 'react' import { Button, Input, IconChevronDown, IconX } from 'ui' -import { useUrlState } from 'hooks' -import { Filter } from 'components/grid/types' +import { Filter, FilterOperator } from 'components/grid/types' import { DropdownControl } from 'components/grid/components/common' import { useTrackedState } from 'components/grid/store' import { FilterOperatorOptions } from './Filter.constants' interface Props { - filter: Filter filterIdx: number + filter: Filter + onChange: (index: number, filter: Filter) => void + onDelete: (index: number) => void } -// [Area of improvement] Input field loses focus after the debounce (because of useUrlState?) -const FilterRow: FC = ({ filter, filterIdx }) => { +const FilterRow: FC = ({ filter, filterIdx, onChange, onDelete }) => { const state = useTrackedState() - const [{ filter: filters }, setParams] = useUrlState({ arrayKeys: ['filter'] }) const column = state.table?.columns.find((x) => x.name === filter.column) const columnOptions = state.table?.columns?.map((x) => { return { value: x.name, label: x.name, postLabel: x.dataType } }) || [] - const [filterValue, setFilterValue] = useState(filter.value) - - useEffect(() => { - setFilterValue(filter.value) - }, [filterIdx]) - - function onRemoveFilter() { - setParams((prevParams) => { - const existingFilters = (prevParams?.filter ?? []) as string[] - const updatedFilters = existingFilters.filter((filter: string, idx: number) => { - if (idx !== filterIdx) return filter - }) - return { - ...prevParams, - filter: updatedFilters, - } - }) - } - - function onColumnChange(column: string | number) { - setParams((prevParams) => { - const existingFilters = (prevParams?.filter ?? []) as string[] - const updatedFilters = existingFilters.map((filter: string, idx: number) => { - if (idx === filterIdx) { - const [_, operator, ...value] = filter.split(':') - const formattedValue = value.join(':') - return `${column}:${operator}:${formattedValue}` - } else { - return filter - } - }) - return { - ...prevParams, - filter: updatedFilters, - } - }) - } - - function onOperatorChange(operator: string | number) { - setParams((prevParams) => { - const existingFilters = (prevParams?.filter ?? []) as string[] - const updatedFilters = existingFilters.map((filter: string, idx: number) => { - if (idx === filterIdx) { - const [column, _, ...value] = filter.split(':') - const formattedValue = value.join(':') - const selectedOperator = FilterOperatorOptions.find((option) => option.value === operator) - return `${column}:${selectedOperator?.abbrev}:${formattedValue}` - } else { - return filter - } - }) - return { - ...prevParams, - filter: updatedFilters, - } - }) - } - - function onValueChange(event: ChangeEvent) { - const value = event.target.value - setFilterValue(value) - debounceHandler({ - filterIdx, - value: { ...filter, value: value }, - }) - } - - const updateFilterValue = (payload: { filterIdx: number; value: Filter }) => { - setParams((prevParams) => { - const existingFilters = (prevParams?.filter ?? []) as string[] - const updatedFilters = existingFilters.map((filter: string, idx: number) => { - if (idx === filterIdx) { - const [column, operator] = filter.split(':') - return `${column}:${operator}:${payload.value.value}` - } else { - return filter - } - }) - return { - ...prevParams, - filter: updatedFilters, - } - }) - } - const debounceHandler = useCallback(debounce(updateFilterValue, 600), [filters]) const placeholder = column?.format === 'timestamptz' @@ -118,7 +31,11 @@ const FilterRow: FC = ({ filter, filterIdx }) => { return (
- + onChange(filterIdx, { ...filter, column: nextColumn as string })} + > - + + onChange(filterIdx, { + ...filter, + operator: nextOperator as FilterOperator, + }) + } + >
) diff --git a/studio/components/grid/components/header/sort/SortPopover.tsx b/studio/components/grid/components/header/sort/SortPopover.tsx index 65e778b1237..f2177bde207 100644 --- a/studio/components/grid/components/header/sort/SortPopover.tsx +++ b/studio/components/grid/components/header/sort/SortPopover.tsx @@ -1,10 +1,13 @@ -import React, { FC } from 'react' +import React, { FC, useState, useMemo, useCallback } from 'react' +import { isEqual } from 'lodash' +import update from 'immutability-helper' import { Button, IconList, IconChevronDown, Popover } from 'ui' - import { useUrlState } from 'hooks' + import SortRow from './SortRow' import { useTrackedState } from 'components/grid/store' import { DropdownControl } from 'components/grid/components/common' +import { Sort } from 'components/grid/types' import { formatSortURLParams } from 'components/grid/SupabaseGrid.utils' const SortPopover: FC = () => { @@ -15,7 +18,7 @@ const SortPopover: FC = () => { : 'Sort' return ( - }> + }> ) : (

All columns have been added

)} + ) diff --git a/studio/components/grid/components/header/sort/SortRow.tsx b/studio/components/grid/components/header/sort/SortRow.tsx index f6fecf5f74c..64a914de7b1 100644 --- a/studio/components/grid/components/header/sort/SortRow.tsx +++ b/studio/components/grid/components/header/sort/SortRow.tsx @@ -1,10 +1,8 @@ -import update from 'immutability-helper' import { FC, useRef, memo } from 'react' import { Button, IconMenu, Toggle, IconX } from 'ui' import { XYCoord } from 'dnd-core' import { useDrag, useDrop, DropTargetMonitor } from 'react-dnd' -import { useUrlState } from 'hooks' import { DragItem, Sort } from 'components/grid/types' import { useTrackedState } from 'components/grid/store' @@ -12,11 +10,13 @@ type SortRowProps = { index: number columnName: string sort: Sort + onDelete: (columnName: string) => void + onToggle: (columnName: string, ascending: boolean) => void + onDrag: (dragIndex: number, hoverIndex: number) => void } -const SortRow: FC = ({ index, columnName, sort }) => { +const SortRow: FC = ({ index, columnName, sort, onDelete, onToggle, onDrag }) => { const state = useTrackedState() - const [_, setParams] = useUrlState({ arrayKeys: ['sort'] }) const column = state?.table?.columns.find((x) => x.name === columnName) if (!column) return null @@ -89,49 +89,9 @@ const SortRow: FC = ({ index, columnName, sort }) => { }, }) - function onToggle(value: boolean) { - setParams((prevParams) => { - const existingSorts = (prevParams?.sort ?? []) as string[] - const updatedSorts = existingSorts.map((sort: string) => { - const [column] = sort.split(':') - return column === columnName ? `${columnName}:${value ? 'asc' : 'desc'}` : sort - }) - return { - ...prevParams, - sort: updatedSorts, - } - }) - } - - function onRemoveSort() { - setParams((prevParams) => { - const existingSorts = (prevParams?.sort ?? []) as string[] - const updatedSorts = existingSorts.filter((sort: string) => { - const [column] = sort.split(':') - if (column !== columnName) return sort - }) - return { - ...prevParams, - sort: updatedSorts, - } - }) - } - const moveSort = (dragIndex: number, hoverIndex: number) => { if (dragIndex == hoverIndex) return - setParams((prevParams) => { - const existingSorts = (prevParams?.sort ?? []) as string[] - const updatedSorts = update(existingSorts, { - $splice: [ - [dragIndex, 1], - [hoverIndex, 0, existingSorts[dragIndex]], - ], - }) - return { - ...prevParams, - sort: updatedSorts, - } - }) + onDrag(dragIndex, hoverIndex) } const opacity = isDragging ? 0 : 1 @@ -144,12 +104,9 @@ const SortRow: FC = ({ index, columnName, sort }) => { style={{ opacity }} data-handler-id={handlerId} > -