Skip to content

Commit

Permalink
fix: Name and kind filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
adityachoudhari26 committed Sep 22, 2024
1 parent 94a680e commit f22bcb6
Show file tree
Hide file tree
Showing 15 changed files with 689 additions and 192 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import type {
ComparisonCondition,
KindEqualsCondition,
} from "@ctrlplane/validators/targets";
import type React from "react";
import { useState } from "react";
import { TbSelector, TbX } from "react-icons/tb";
import { z } from "zod";

import { Badge } from "@ctrlplane/ui/badge";
import { Button } from "@ctrlplane/ui/button";
import {
Command,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@ctrlplane/ui/command";
import {
Dialog,
DialogContent,
DialogFooter,
DialogTitle,
DialogTrigger,
} from "@ctrlplane/ui/dialog";
import {
Form,
FormControl,
FormField,
FormItem,
useFieldArray,
useForm,
} from "@ctrlplane/ui/form";
import { Popover, PopoverContent, PopoverTrigger } from "@ctrlplane/ui/popover";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@ctrlplane/ui/select";
import {
kindEqualsCondition,
TargetFilterType,
TargetOperator,
} from "@ctrlplane/validators/targets";

import type { TargetFilter } from "./TargetFilter";

const kindFilterForm = z.object({
operator: z.enum(["and", "or"]),
targetFilter: z.array(kindEqualsCondition),
});

export const KindFilterDialog: React.FC<{
kinds: string[];
children: React.ReactNode;
onChange?: (filter: TargetFilter) => void;
filter?: ComparisonCondition;
}> = ({ kinds, children, onChange, filter }) => {
const [open, setOpen] = useState(false);
const [commandOpen, setCommandOpen] = useState(false);
const form = useForm({
schema: kindFilterForm,
defaultValues: {
operator:
filter?.operator === TargetOperator.Or
? TargetOperator.Or
: TargetOperator.And,
targetFilter:
(filter?.conditions as KindEqualsCondition[] | undefined) ?? [],
},
});

const { fields, append, remove } = useFieldArray({
control: form.control,
name: "targetFilter",
});

const onSubmit = form.handleSubmit((values) => {
const cond = {
type: TargetFilterType.Comparison as const,
operator: values.operator,
conditions: values.targetFilter,
};
onChange?.({ key: "kind", value: cond });
setOpen(false);
});

const newKinds = kinds.filter(
(kind) => !fields.some((field) => field.value === kind),
);

return (
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger asChild>{children}</DialogTrigger>
<DialogContent>
<Form {...form}>
<form onSubmit={onSubmit} className="space-y-4">
<DialogTitle>Filter by kind</DialogTitle>

{fields.length > 1 && (
<FormField
control={form.control}
name="operator"
render={({ field: { onChange, value } }) => (
<FormItem className="w-24">
<FormControl>
<Select value={value} onValueChange={onChange}>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="and">And</SelectItem>
<SelectItem value="or">Or</SelectItem>
</SelectContent>
</Select>
</FormControl>
</FormItem>
)}
/>
)}

{fields.map((field, index) => (
<FormField
key={field.id}
control={form.control}
name={`targetFilter.${index}`}
render={({ field: { value } }) => (
<Badge
key={field.id}
variant="secondary"
className="flex w-fit items-center gap-2 p-1"
>
{value.value}
<Button
variant="ghost"
size="icon"
className="h-4 w-4"
onClick={() => remove(index)}
>
<TbX />
</Button>
</Badge>
)}
/>
))}

<div className="flex gap-2">
<Popover open={commandOpen} onOpenChange={setCommandOpen}>
<PopoverTrigger asChild>
<Button
variant="outline"
role="combobox"
aria-expanded={commandOpen}
className="w-full items-center justify-start gap-2 px-2"
>
<TbSelector />
<span>Select kind...</span>
</Button>
</PopoverTrigger>
<PopoverContent align="start" className="w-[462px] p-0">
<Command>
<CommandInput placeholder="Search kind..." />
<CommandGroup>
<CommandList>
{newKinds.length === 0 && (
<CommandItem disabled>No kinds to add</CommandItem>
)}
{newKinds
.filter(
(kind) =>
!fields.some((field) => field.value === kind),
)
.map((kind) => (
<CommandItem
key={kind}
value={kind}
onSelect={() => {
append({
operator: "equals",
value: kind,
type: "kind",
});
setCommandOpen(false);
}}
>
{kind}
</CommandItem>
))}
</CommandList>
</CommandGroup>
</Command>
</PopoverContent>
</Popover>
</div>

<DialogFooter>
<Button type="submit">Filter</Button>
</DialogFooter>
</form>
</Form>
</DialogContent>
</Dialog>
);
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import type {
ComparisonCondition,
EqualCondition,
LikeCondition,
NullCondition,
RegexCondition,
MetadataCondition,
} from "@ctrlplane/validators/targets";
import { useState } from "react";
import _ from "lodash";
Expand Down Expand Up @@ -33,20 +30,17 @@ import {
SelectValue,
} from "@ctrlplane/ui/select";
import {
equalsCondition,
likeCondition,
nullCondition,
regexCondition,
metadataCondition,
TargetFilterType,
TargetOperator,
} from "@ctrlplane/validators/targets";

import type { TargetFilter } from "./TargetFilter";
import { MetadataFilterInput } from "../../_components/MetadataFilterInput";

const metadataFilterForm = z.object({
operator: z.enum(["and", "or"]),
targetFilter: z.array(
z.union([likeCondition, regexCondition, equalsCondition, nullCondition]),
),
targetFilter: z.array(metadataCondition),
});

export const MetadataFilterDialog: React.FC<{
Expand All @@ -59,10 +53,18 @@ export const MetadataFilterDialog: React.FC<{
const form = useForm({
schema: metadataFilterForm,
defaultValues: {
operator: "and" as const,
targetFilter: (filter?.conditions as
| (LikeCondition | RegexCondition | EqualCondition | NullCondition)[]
| undefined) ?? [{ key: "", value: "", operator: "equals" }],
operator:
filter?.operator === TargetOperator.Or
? TargetOperator.Or
: TargetOperator.And,
targetFilter: (filter?.conditions as MetadataCondition[] | undefined) ?? [
{
key: "",
value: "",
operator: TargetOperator.Equals,
type: TargetFilterType.Metadata,
},
],
},
});

Expand All @@ -73,6 +75,7 @@ export const MetadataFilterDialog: React.FC<{

const onSubmit = form.handleSubmit((values) => {
const cond = {
type: TargetFilterType.Comparison as const,
operator: values.operator,
conditions: values.targetFilter,
};
Expand Down Expand Up @@ -140,7 +143,14 @@ export const MetadataFilterDialog: React.FC<{
variant="outline"
size="sm"
className="mt-4"
onClick={() => append({ key: "", value: "", operator: "equals" })}
onClick={() =>
append({
key: "",
value: "",
operator: "equals",
type: "metadata",
})
}
>
Add Metadata Key
</Button>
Expand Down
Loading

0 comments on commit f22bcb6

Please sign in to comment.