diff --git a/apps/start/src/components/overview/filters/origin-filter.tsx b/apps/start/src/components/overview/filters/origin-filter.tsx
index a1251985..248250cf 100644
--- a/apps/start/src/components/overview/filters/origin-filter.tsx
+++ b/apps/start/src/components/overview/filters/origin-filter.tsx
@@ -1,10 +1,8 @@
-import { Button } from '@/components/ui/button';
import { useAppParams } from '@/hooks/use-app-params';
import { useEventQueryFilters } from '@/hooks/use-event-query-filters';
import { useTRPC } from '@/integrations/trpc/react';
import { cn } from '@/utils/cn';
import { useQuery } from '@tanstack/react-query';
-import { GlobeIcon } from 'lucide-react';
export function OriginFilter() {
const { projectId } = useAppParams();
@@ -14,12 +12,8 @@ export function OriginFilter() {
const { data } = useQuery(
trpc.event.origin.queryOptions(
- {
- projectId: projectId,
- },
- {
- staleTime: 1000 * 60 * 60,
- },
+ { projectId },
+ { staleTime: 1000 * 60 * 60 },
),
);
@@ -28,20 +22,23 @@ export function OriginFilter() {
}
return (
-
- {data?.map((item) => {
+
+ {data.map((item) => {
+ const active = originFilter?.value.includes(item.origin);
return (
-
+
);
})}
diff --git a/apps/start/src/components/overview/filters/overview-filters-buttons.tsx b/apps/start/src/components/overview/filters/overview-filters-buttons.tsx
index 27a27741..966a30dc 100644
--- a/apps/start/src/components/overview/filters/overview-filters-buttons.tsx
+++ b/apps/start/src/components/overview/filters/overview-filters-buttons.tsx
@@ -1,13 +1,21 @@
import { Button } from '@/components/ui/button';
+import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
+import { FilterOperatorSelect } from '@/components/report/sidebar/filters/FilterOperatorSelect';
+import { useAppParams } from '@/hooks/use-app-params';
import {
useEventQueryFilters,
useEventQueryNamesFilter,
} from '@/hooks/use-event-query-filters';
+import { usePropertyValues } from '@/hooks/use-property-values';
import { pushModal } from '@/modals';
import type { OverviewFiltersProps } from '@/modals/overview-filters';
import { getPropertyLabel } from '@/translations/properties';
import { cn } from '@/utils/cn';
import { operators } from '@openpanel/constants';
+import type {
+ IChartEventFilter,
+ IChartEventFilterOperator,
+} from '@openpanel/validation';
import { FilterIcon, X } from 'lucide-react';
import type { Options as NuqsOptions } from 'nuqs';
@@ -33,14 +41,95 @@ export function OverviewFilterButton(props: OverviewFiltersProps) {
);
}
+interface FilterPillProps {
+ filter: IChartEventFilter;
+ nuqsOptions?: NuqsOptions;
+ onRemove: () => void;
+ onChangeOperator: (operator: IChartEventFilterOperator) => void;
+ onChangeValue: (value: string[]) => void;
+}
+
+function FilterPill({
+ filter,
+ nuqsOptions,
+ onRemove,
+ onChangeOperator,
+ onChangeValue,
+}: FilterPillProps) {
+ const { projectId } = useAppParams();
+ const potentialValues = usePropertyValues({
+ event: '*',
+ property: filter.name,
+ projectId,
+ });
+
+ const noValueNeeded =
+ filter.operator === 'isNull' || filter.operator === 'isNotNull';
+
+ return (
+
+ {/* Key — opens modal to change the property */}
+
+
+ {/* Operator dropdown */}
+
+
+
+
+ {/* Value picker — only when operator needs a value */}
+ {!noValueNeeded && (
+ ({ value: v, label: v }))}
+ value={filter.value}
+ onChange={onChangeValue}
+ >
+
+
+ )}
+
+ {/* Remove */}
+
+
+ );
+}
+
export function OverviewFiltersButtons({
className,
nuqsOptions,
}: OverviewFiltersButtonsProps) {
const [events, setEvents] = useEventQueryNamesFilter(nuqsOptions);
- const [filters, _setFilter, _setFilters, removeFilter] =
+ const [filters, setFilter, _setFilters, removeFilter] =
useEventQueryFilters(nuqsOptions);
+
if (filters.length === 0 && events.length === 0) return null;
+
return (
{events.map((event) => (
@@ -54,27 +143,20 @@ export function OverviewFiltersButtons({
{event}
))}
- {filters.map((filter) => {
- return (
-
- );
- })}
+ {filters.map((filter) => (
+ removeFilter(filter.name)}
+ onChangeOperator={(operator) =>
+ setFilter(filter.name, filter.value, operator)
+ }
+ onChangeValue={(value) =>
+ setFilter(filter.name, value, filter.operator)
+ }
+ />
+ ))}
);
}
diff --git a/apps/start/src/components/report/sidebar/filters/FilterItem.tsx b/apps/start/src/components/report/sidebar/filters/FilterItem.tsx
index 1a2d6be2..e9a3dc57 100644
--- a/apps/start/src/components/report/sidebar/filters/FilterItem.tsx
+++ b/apps/start/src/components/report/sidebar/filters/FilterItem.tsx
@@ -1,20 +1,19 @@
import { ColorSquare } from '@/components/color-square';
+import { FilterOperatorSelect } from '@/components/report/sidebar/filters/FilterOperatorSelect';
import { RenderDots } from '@/components/ui/RenderDots';
import { Button } from '@/components/ui/button';
import { ComboboxAdvanced } from '@/components/ui/combobox-advanced';
-import { DropdownMenuComposed } from '@/components/ui/dropdown-menu';
import { InputEnter } from '@/components/ui/input-enter';
import { useAppParams } from '@/hooks/use-app-params';
import { usePropertyValues } from '@/hooks/use-property-values';
import { useDispatch } from '@/redux';
-import { operators } from '@openpanel/constants';
import type {
IChartEvent,
IChartEventFilter,
IChartEventFilterOperator,
IChartEventFilterValue,
} from '@openpanel/validation';
-import { mapKeys } from '@openpanel/validation';
+
import { SlidersHorizontal, Trash } from 'lucide-react';
import { changeEvent } from '../../reportSlice';
@@ -155,18 +154,10 @@ export function PureFilterItem({