chore: clean up ColumnFilterType (#18915)

This commit is contained in:
Eunjae Lee
2025-01-27 17:13:10 +01:00
committed by GitHub
parent f06bac7129
commit 61a2a3ef5a
13 changed files with 84 additions and 71 deletions
@@ -10,7 +10,7 @@ import { Select } from "@calcom/ui";
import "../../../insights/filters/DateSelect.css";
import { useDataTable, useFilterValue } from "../../hooks";
import type { FilterableColumn } from "../../lib/types";
import { ZDateRangeFilterValue } from "../../lib/types";
import { ZDateRangeFilterValue, ColumnFilterType } from "../../lib/types";
type PresetOption = {
labelKey: string;
@@ -20,7 +20,7 @@ type PresetOption = {
type DateRangeFilterProps = {
className?: string;
column: Extract<FilterableColumn, { type: "date_range" }>;
column: Extract<FilterableColumn, { type: ColumnFilterType.DATE_RANGE }>;
};
const CUSTOM_PRESET_VALUE = "c" as const;
@@ -112,7 +112,7 @@ export const DateRangeFilter = ({ className, column }: DateRangeFilterProps) =>
if (startDate && endDate) {
updateFilter(column.id, {
type: "date_range",
type: ColumnFilterType.DATE_RANGE,
data: {
startDate: startDate.toDate().toISOString(),
endDate: endDate.toDate().toISOString(),
@@ -1,6 +1,7 @@
"use client";
import type { FilterableColumn } from "../../lib/types";
import { ColumnFilterType } from "../../lib/types";
import { DateRangeFilter } from "./DateRangeFilter";
import { MultiSelectFilterOptions } from "./MultiSelectFilterOptions";
import { NumberFilterOptions } from "./NumberFilterOptions";
@@ -12,15 +13,15 @@ export type FilterOptionsProps = {
};
export function FilterOptions({ column }: FilterOptionsProps) {
if (column.type === "text") {
if (column.type === ColumnFilterType.TEXT) {
return <TextFilterOptions column={column} />;
} else if (column.type === "multi_select") {
} else if (column.type === ColumnFilterType.MULTI_SELECT) {
return <MultiSelectFilterOptions column={column} />;
} else if (column.type === "single_select") {
} else if (column.type === ColumnFilterType.SINGLE_SELECT) {
return <SingleSelectFilterOptions column={column} />;
} else if (column.type === "number") {
} else if (column.type === ColumnFilterType.NUMBER) {
return <NumberFilterOptions column={column} />;
} else if (column.type === "date_range") {
} else if (column.type === ColumnFilterType.DATE_RANGE) {
return <DateRangeFilter column={column} />;
} else {
return null;
@@ -5,7 +5,7 @@ import type { IconName } from "@calcom/ui";
import { Button, Icon, Popover, PopoverContent, PopoverTrigger } from "@calcom/ui";
import { useFilterValue } from "../../hooks";
import { type FilterableColumn, type FilterValue, ZFilterValue } from "../../lib/types";
import { type FilterableColumn, type FilterValue, ZFilterValue, ColumnFilterType } from "../../lib/types";
import {
isSingleSelectFilterValue,
isMultiSelectFilterValue,
@@ -14,12 +14,12 @@ import {
} from "../../lib/utils";
import { FilterOptions } from "./FilterOptions";
const FILTER_ICONS: Record<FilterableColumn["type"], IconName> = {
text: "file-text",
number: "binary",
multi_select: "layers",
single_select: "disc",
date_range: "calendar-range",
const FILTER_ICONS: Record<ColumnFilterType, IconName> = {
[ColumnFilterType.TEXT]: "file-text",
[ColumnFilterType.NUMBER]: "binary",
[ColumnFilterType.MULTI_SELECT]: "layers",
[ColumnFilterType.SINGLE_SELECT]: "disc",
[ColumnFilterType.DATE_RANGE]: "calendar-range",
};
type FilterPopoverProps = {
@@ -38,11 +38,11 @@ const useSelectedLabels = ({
} else if (isNumberFilterValue(filterValue)) {
return { text: filterValue.data.operand, moreCount: 0 };
} else if (isSingleSelectFilterValue(filterValue)) {
const options = (column as Extract<FilterableColumn, { type: "single_select" }>).options;
const options = (column as Extract<FilterableColumn, { type: ColumnFilterType.SINGLE_SELECT }>).options;
const text = options.find((opt) => opt.value === filterValue.data)?.label;
return { text, moreCount: 0 };
} else if (isMultiSelectFilterValue(filterValue)) {
const options = (column as Extract<FilterableColumn, { type: "multi_select" }>).options;
const options = (column as Extract<FilterableColumn, { type: ColumnFilterType.MULTI_SELECT }>).options;
const text = options.find((opt) => opt.value === filterValue.data[0])?.label;
return { text, moreCount: filterValue.data.length - 1 };
} else {
@@ -54,6 +54,11 @@ export function FilterPopover({ column }: FilterPopoverProps) {
const icon = column.icon || FILTER_ICONS[column.type];
const filterValue = useFilterValue(column.id, ZFilterValue);
const { text, moreCount } = useSelectedLabels({ column, filterValue });
console.log("💡 icon", {
icon: column.icon,
type: column.type,
FILTER_ICONS,
});
return (
<Popover>
<PopoverTrigger asChild>
@@ -16,10 +16,10 @@ import {
import { useDataTable, useFilterValue } from "../../hooks";
import type { FilterableColumn } from "../../lib/types";
import { ZMultiSelectFilterValue } from "../../lib/types";
import { ZMultiSelectFilterValue, ColumnFilterType } from "../../lib/types";
export type MultiSelectFilterOptionsProps = {
column: Extract<FilterableColumn, { type: "multi_select" }>;
column: Extract<FilterableColumn, { type: ColumnFilterType.MULTI_SELECT }>;
};
export function MultiSelectFilterOptions({ column }: MultiSelectFilterOptionsProps) {
@@ -44,7 +44,7 @@ export function MultiSelectFilterOptions({ column }: MultiSelectFilterOptionsPro
const newFilterValue = filterValue?.data.includes(optionValue)
? filterValue?.data.filter((value) => value !== optionValue)
: [...(filterValue?.data || []), optionValue];
updateFilter(column.id, { type: "multi_select", data: newFilterValue });
updateFilter(column.id, { type: ColumnFilterType.MULTI_SELECT, data: newFilterValue });
}}>
<div
className={classNames(
@@ -7,7 +7,7 @@ import { Form, Input, Select, Button } from "@calcom/ui";
import { useFilterValue, useDataTable } from "../../hooks";
import type { FilterableColumn, NumberFilterOperator } from "../../lib/types";
import { ZNumberFilterValue } from "../../lib/types";
import { ZNumberFilterValue, ColumnFilterType } from "../../lib/types";
export type NumberFilterOperatorOption = {
label: string;
@@ -24,7 +24,7 @@ const numberFilterOperatorOptions: NumberFilterOperatorOption[] = [
];
export type NumberFilterOptionsProps = {
column: Extract<FilterableColumn, { type: "number" }>;
column: Extract<FilterableColumn, { type: ColumnFilterType.NUMBER }>;
};
export function NumberFilterOptions({ column }: NumberFilterOptionsProps) {
@@ -48,7 +48,7 @@ export function NumberFilterOptions({ column }: NumberFilterOptionsProps) {
handleSubmit={({ operatorOption, operand }) => {
if (operatorOption) {
updateFilter(column.id, {
type: "number",
type: ColumnFilterType.NUMBER,
data: {
operator: operatorOption.value,
operand: Number(operand),
@@ -16,10 +16,10 @@ import {
import { useDataTable, useFilterValue } from "../../hooks";
import type { FilterableColumn } from "../../lib/types";
import { ZSingleSelectFilterValue } from "../../lib/types";
import { ZSingleSelectFilterValue, ColumnFilterType } from "../../lib/types";
export type SingleSelectFilterOptionsProps = {
column: Extract<FilterableColumn, { type: "single_select" }>;
column: Extract<FilterableColumn, { type: ColumnFilterType.SINGLE_SELECT }>;
};
export function SingleSelectFilterOptions({ column }: SingleSelectFilterOptionsProps) {
@@ -41,7 +41,7 @@ export function SingleSelectFilterOptions({ column }: SingleSelectFilterOptionsP
<CommandItem
key={optionValue}
onSelect={() => {
updateFilter(column.id, { type: "single_select", data: optionValue });
updateFilter(column.id, { type: ColumnFilterType.SINGLE_SELECT, data: optionValue });
}}>
<div
className={classNames(
@@ -7,7 +7,7 @@ import { Form, Input, Select, Button } from "@calcom/ui";
import { useFilterValue, useDataTable } from "../../hooks";
import type { FilterableColumn, TextFilterOperator } from "../../lib/types";
import { ZTextFilterValue } from "../../lib/types";
import { ZTextFilterValue, ColumnFilterType } from "../../lib/types";
export type TextFilterOperatorOption = {
label: string;
@@ -30,7 +30,7 @@ const useTextFilterOperatorOptions = (): TextFilterOperatorOption[] => {
};
export type TextFilterOptionsProps = {
column: Extract<FilterableColumn, { type: "text" }>;
column: Extract<FilterableColumn, { type: ColumnFilterType.TEXT }>;
};
export function TextFilterOptions({ column }: TextFilterOptionsProps) {
@@ -55,7 +55,7 @@ export function TextFilterOptions({ column }: TextFilterOptionsProps) {
handleSubmit={({ operatorOption, operand }) => {
if (operatorOption) {
updateFilter(column.id, {
type: "text",
type: ColumnFilterType.TEXT,
data: {
operator: operatorOption.value,
operand: operatorOption.requiresOperand ? operand : "",
@@ -5,6 +5,7 @@ import { type Table } from "@tanstack/react-table";
import { useMemo } from "react";
import type { FilterableColumn } from "../lib/types";
import { ColumnFilterType } from "../lib/types";
export function useFilterableColumns<TData>(table: Table<TData>) {
const columns = useMemo(
@@ -16,14 +17,14 @@ export function useFilterableColumns<TData>(table: Table<TData>) {
() =>
columns
.map((column) => {
const type = column.columnDef.meta?.filter?.type || "multi_select";
const type = column.columnDef.meta?.filter?.type || ColumnFilterType.MULTI_SELECT;
const base = {
id: column.id,
title: typeof column.columnDef.header === "string" ? column.columnDef.header : column.id,
...(column.columnDef.meta?.filter || {}),
type,
};
if (type === "multi_select" || type === "single_select") {
if (type === ColumnFilterType.MULTI_SELECT || type === ColumnFilterType.SINGLE_SELECT) {
const values = column.getFacetedUniqueValues();
const options = Array.from(values.keys()).map((option) => {
if (typeof option === "string") {
+24 -22
View File
@@ -2,6 +2,14 @@ import { z } from "zod";
import type { IconName } from "@calcom/ui";
export enum ColumnFilterType {
SINGLE_SELECT = "ss",
MULTI_SELECT = "ms",
TEXT = "t",
NUMBER = "n",
DATE_RANGE = "dr",
}
export const ZTextFilterOperator = z.enum([
"equals",
"notEquals",
@@ -16,21 +24,21 @@ export const ZTextFilterOperator = z.enum([
export type TextFilterOperator = z.infer<typeof ZTextFilterOperator>;
export const ZSingleSelectFilterValue = z.object({
type: z.literal("single_select"),
type: z.literal(ColumnFilterType.SINGLE_SELECT),
data: z.union([z.string(), z.number()]),
});
export type SingleSelectFilterValue = z.infer<typeof ZSingleSelectFilterValue>;
export const ZMultiSelectFilterValue = z.object({
type: z.literal("multi_select"),
type: z.literal(ColumnFilterType.MULTI_SELECT),
data: z.union([z.string(), z.number()]).array(),
});
export type MultiSelectFilterValue = z.infer<typeof ZMultiSelectFilterValue>;
export const ZTextFilterValue = z.object({
type: z.literal("text"),
type: z.literal(ColumnFilterType.TEXT),
data: z.object({
operator: ZTextFilterOperator,
operand: z.string(),
@@ -51,7 +59,7 @@ export const ZNumberFilterOperator = z.enum([
export type NumberFilterOperator = z.infer<typeof ZNumberFilterOperator>;
export const ZNumberFilterValue = z.object({
type: z.literal("number"),
type: z.literal(ColumnFilterType.NUMBER),
data: z.object({
operator: ZNumberFilterOperator,
operand: z.number(),
@@ -61,7 +69,7 @@ export const ZNumberFilterValue = z.object({
export type NumberFilterValue = z.infer<typeof ZNumberFilterValue>;
export const ZDateRangeFilterValue = z.object({
type: z.literal("date_range"),
type: z.literal(ColumnFilterType.DATE_RANGE),
data: z.object({
startDate: z.string().nullable(),
endDate: z.string().nullable(),
@@ -81,8 +89,6 @@ export const ZFilterValue = z.union([
export type FilterValue = z.infer<typeof ZFilterValue>;
export type ColumnFilterType = "single_select" | "multi_select" | "text" | "number" | "date_range";
export type ColumnFilterMeta = {
type?: ColumnFilterType;
icon?: IconName;
@@ -91,28 +97,24 @@ export type ColumnFilterMeta = {
export type FilterableColumn = {
id: string;
title: string;
icon?: IconName;
} & (
| {
type: "single_select";
icon?: IconName;
type: ColumnFilterType.SINGLE_SELECT;
options: Array<{ label: string; value: string | number }>;
}
| {
type: "multi_select";
icon?: IconName;
type: ColumnFilterType.MULTI_SELECT;
options: Array<{ label: string; value: string | number }>;
}
| {
type: "text";
icon?: IconName;
type: ColumnFilterType.TEXT;
}
| {
type: "number";
icon?: IconName;
type: ColumnFilterType.NUMBER;
}
| {
type: "date_range";
icon?: IconName;
type: ColumnFilterType.DATE_RANGE;
}
);
@@ -125,15 +127,15 @@ export type ColumnFilter = z.infer<typeof ZColumnFilter>;
export type TypedColumnFilter<T extends ColumnFilterType> = {
id: string;
value: T extends "text"
value: T extends ColumnFilterType.TEXT
? TextFilterValue
: T extends "number"
: T extends ColumnFilterType.NUMBER
? NumberFilterValue
: T extends "single_select"
: T extends ColumnFilterType.SINGLE_SELECT
? SingleSelectFilterValue
: T extends "multi_select"
: T extends ColumnFilterType.MULTI_SELECT
? MultiSelectFilterValue
: T extends "date_range"
: T extends ColumnFilterType.DATE_RANGE
? DateRangeFilterValue
: never;
};
@@ -31,6 +31,7 @@ import {
ZMultiSelectFilterValue,
ZSingleSelectFilterValue,
DateRangeFilter,
ColumnFilterType,
type FilterableColumn,
} from "@calcom/features/data-table";
import classNames from "@calcom/lib/classNames";
@@ -261,10 +262,10 @@ export function RoutingFormResponsesTable() {
);
}
const createdAtColumn: Extract<FilterableColumn, { type: "date_range" }> = {
const createdAtColumn: Extract<FilterableColumn, { type: ColumnFilterType.DATE_RANGE }> = {
id: "createdAt",
title: "createdAt",
type: "date_range",
type: ColumnFilterType.DATE_RANGE,
};
export function RoutingFormResponsesTableContent() {
@@ -354,7 +355,7 @@ export function RoutingFormResponsesTableContent() {
enableColumnFilter: true,
enableSorting: false,
meta: {
filter: { type: "single_select" },
filter: { type: ColumnFilterType.SINGLE_SELECT },
},
cell: () => null,
}),
@@ -364,7 +365,7 @@ export function RoutingFormResponsesTableContent() {
enableColumnFilter: true,
enableSorting: false,
meta: {
filter: { type: "multi_select" },
filter: { type: ColumnFilterType.MULTI_SELECT },
},
cell: () => null,
}),
@@ -393,12 +394,12 @@ export function RoutingFormResponsesTableContent() {
const isMultiSelect = fieldHeader.type === RoutingFormFieldType.MULTI_SELECT;
const filterType = isSingleSelect
? "single_select"
? ColumnFilterType.SINGLE_SELECT
: isNumber
? "number"
? ColumnFilterType.NUMBER
: isText
? "text"
: "multi_select";
? ColumnFilterType.TEXT
: ColumnFilterType.MULTI_SELECT;
const optionMap =
fieldHeader.options?.reduce((acc, option) => {
@@ -457,7 +458,7 @@ export function RoutingFormResponsesTableContent() {
</div>
),
meta: {
filter: { type: "multi_select", icon: "circle" },
filter: { type: ColumnFilterType.MULTI_SELECT, icon: "circle" },
},
filterFn: (row, id, filterValue) => {
return multiSelectFilter(row.original.bookingStatusOrder, filterValue);
@@ -498,7 +499,7 @@ export function RoutingFormResponsesTableContent() {
header: t("routing_form_insights_assignment_reason"),
enableSorting: false,
meta: {
filter: { type: "text" },
filter: { type: ColumnFilterType.TEXT },
},
cell: (info) => {
const assignmentReason = info.getValue();
@@ -9,7 +9,8 @@ import {
routingFormResponseInDbSchema,
} from "@calcom/app-store/routing-forms/zod";
import dayjs from "@calcom/dayjs";
import type { ColumnFilter, TypedColumnFilter, ColumnFilterType } from "@calcom/features/data-table";
import type { ColumnFilter, TypedColumnFilter } from "@calcom/features/data-table";
import { ColumnFilterType } from "@calcom/features/data-table";
import { makeWhereClause, makeOrderBy } from "@calcom/features/data-table/lib/server";
import type { RoutingFormResponsesInput } from "@calcom/features/insights/server/raw-data.schema";
import { readonlyPrisma as prisma } from "@calcom/prisma";
@@ -235,7 +236,7 @@ class RoutingEventsInsights {
});
const getLowercasedFilterValue = <TData extends ColumnFilterType>(filter: TypedColumnFilter<TData>) => {
if (filter.value.type === "text") {
if (filter.value.type === ColumnFilterType.TEXT) {
return {
...filter.value,
data: {
@@ -250,7 +251,7 @@ class RoutingEventsInsights {
const bookingStatusOrder = columnFilters.find((filter) => filter.id === "bookingStatusOrder");
const bookingAssignmentReason = columnFilters.find(
(filter) => filter.id === "bookingAssignmentReason"
) as TypedColumnFilter<"text"> | undefined;
) as TypedColumnFilter<ColumnFilterType.TEXT> | undefined;
const assignmentReasonValue = bookingAssignmentReason
? getLowercasedFilterValue(bookingAssignmentReason)
: undefined;
@@ -19,6 +19,7 @@ import {
isMultiSelectFilterValue,
singleSelectFilter,
multiSelectFilter,
ColumnFilterType,
} from "@calcom/features/data-table";
import { useOrgBranding } from "@calcom/features/ee/organizations/context/provider";
import classNames from "@calcom/lib/classNames";
@@ -184,12 +185,12 @@ function UserListTableContent() {
const isSingleSelect = attribute.type === "SINGLE_SELECT";
const isMultiSelect = attribute.type === "MULTI_SELECT";
const filterType = isNumber
? "number"
? ColumnFilterType.NUMBER
: isText
? "text"
? ColumnFilterType.TEXT
: isSingleSelect
? "single_select"
: "multi_select";
? ColumnFilterType.SINGLE_SELECT
: ColumnFilterType.MULTI_SELECT;
return {
id: attribute.id,
@@ -1,4 +1,5 @@
import { makeWhereClause } from "@calcom/features/data-table/lib/server";
import { ColumnFilterType } from "@calcom/features/data-table/lib/types";
import { UserRepository } from "@calcom/lib/server/repository/user";
import { prisma } from "@calcom/prisma";
import type { Prisma } from "@calcom/prisma/client";
@@ -122,7 +123,7 @@ export const listMembersHandler = async ({ ctx, input }: GetOptions) => {
break;
// We assume that if the filter is not one of the above, it must be an attribute filter
default:
if (filter.value.type === "multi_select" && isAllString(filter.value.data)) {
if (filter.value.type === ColumnFilterType.MULTI_SELECT && isAllString(filter.value.data)) {
const attributeOptionValues: string[] = [];
filter.value.data.forEach((filterValueItem) => {
attributeOptionValues.push(filterValueItem);