Skip to content

Commit

Permalink
feat: working
Browse files Browse the repository at this point in the history
  • Loading branch information
talboren committed Feb 19, 2024
1 parent 7a7b6a2 commit c354646
Show file tree
Hide file tree
Showing 7 changed files with 224 additions and 15 deletions.
34 changes: 29 additions & 5 deletions keep-ui/app/mapping/mapping.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
"use client";
import { Badge, Card } from "@tremor/react";
import { Badge, Callout, Card } from "@tremor/react";
import CreateNewMapping from "./create-new-mapping";
import { useMappings } from "utils/hooks/useMappingRules";
import RulesTable from "./rules-table";
import { MdWarning } from "react-icons/md";
import Loading from "app/loading";
export default function Mapping() {
const { data: mappings, mutate } = useMappings();
const { data: mappings, isLoading } = useMappings();

return (
<Card className="p-4 md:p-10 mx-auto">
<Badge color="orange" size="xs" tooltip="Slack us if something isn't working properly :)" className="absolute top-[-10px] left-[-10px]">Beta</Badge>
<Badge
color="orange"
size="xs"
tooltip="Slack us if something isn't working properly :)"
className="absolute top-[-10px] left-[-10px]"
>
Beta
</Badge>
<div className="flex divide-x p-2">
<div className="w-1/3 pr-2.5">
<h2 className="text-lg">Configure</h2>
Expand All @@ -18,8 +28,22 @@ export default function Mapping() {
</div>

<div className="w-2/3 pl-2.5">
<h2 className="text-lg">Rules</h2>
{mappings && mappings.length > 0 ? <>Rules!</> : <>No Rules!</>}
{isLoading ? (
<Loading />
) : mappings && mappings.length > 0 ? (
<RulesTable mappings={mappings} />
) : (
<Callout
color="orange"
title="Mapping rules does not exist"
icon={MdWarning}
>
<p className="text-slate-400">No mapping rules found</p>
<p className="text-slate-400">
Configure new mapping rule using the mapping rules wizard.
</p>
</Callout>
)}
</div>
</div>
</Card>
Expand Down
6 changes: 5 additions & 1 deletion keep-ui/app/mapping/models.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
export interface MappingRule {
id?: number;
id: number;
tenant_id: string;
priority: number;
name: string;
description?: string;
file_name?: string;
created_by?: string;
created_at: Date;
disabled: boolean;
override: boolean;
condition?: string;
matchers: string[];
rows: { [key: string]: any }[];
attributes?: string[];
}
150 changes: 150 additions & 0 deletions keep-ui/app/mapping/rules-table.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import {
Badge,
Button,
Table,
TableBody,
TableCell,
TableHead,
TableHeaderCell,
TableRow,
} from "@tremor/react";
import { MappingRule } from "./models";
import {
DisplayColumnDef,
createColumnHelper,
flexRender,
getCoreRowModel,
useReactTable,
} from "@tanstack/react-table";
import { MdRemoveCircle } from "react-icons/md";
import { useSession } from "next-auth/react";
import { getApiURL } from "utils/apiUrl";
import { useMappings } from "utils/hooks/useMappingRules";
import { toast } from "react-toastify";

const columnHelper = createColumnHelper<MappingRule>();

export default function RulesTable({ mappings }: { mappings: MappingRule[] }) {
const { data: session } = useSession();
const { mutate } = useMappings();

const columns = [
columnHelper.display({
id: "id",
header: "#",
cell: (context) => context.row.original.id,
}),
columnHelper.display({
id: "name",
header: "Name",
cell: (context) => context.row.original.name,
}),
columnHelper.display({
id: "description",
header: "Description",
cell: (context) => context.row.original.description,
}),
columnHelper.display({
id: "fileName",
header: "Original File Name",
cell: (context) => context.row.original.file_name,
}),
columnHelper.display({
id: "matchers",
header: "Matchers",
cell: (context) => context.row.original.matchers.join(","),
}),
columnHelper.display({
id: "attributes",
header: "Attributes",
cell: (context) => (
<div className="flex flex-wrap">
{context.row.original.attributes?.map((attr) => (
<Badge key={attr} color="orange" size="xs">
{attr}
</Badge>
))}
</div>
),
}),
columnHelper.display({
id: "delete",
header: "",
cell: (context) => (
<Button
color="red"
size="xs"
variant="secondary"
icon={MdRemoveCircle}
onClick={() => deleteRule(context.row.original.id!)}
/>
),
}),
] as DisplayColumnDef<MappingRule>[];

const table = useReactTable({
columns,
data: mappings,
getCoreRowModel: getCoreRowModel(),
});

const deleteRule = (ruleId: number) => {
const apiUrl = getApiURL();
if (confirm("Are you sure you want to delete this rule?")) {
fetch(`${apiUrl}/mapping/${ruleId}`, {
method: "DELETE",
headers: {
Authorization: `Bearer ${session?.accessToken}`,
},
}).then((response) => {
if (response.ok) {
mutate();
toast.success("Rule deleted successfully");
} else {
toast.error("Failed to delete rule, contact us if this persists");
}
});
}
};

return (
<Table>
<TableHead>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow
className="border-b border-tremor-border dark:border-dark-tremor-border"
key={headerGroup.id}
>
{headerGroup.headers.map((header) => {
return (
<TableHeaderCell
className="text-tremor-content-strong dark:text-dark-tremor-content-strong"
key={header.id}
>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
</TableHeaderCell>
);
})}
</TableRow>
))}
</TableHead>
<TableBody>
{table.getRowModel().rows.map((row) => (
<TableRow
className="even:bg-tremor-background-muted even:dark:bg-dark-tremor-background-muted hover:bg-slate-100"
key={row.id}
>
{row.getVisibleCells().map((cell) => (
<TableCell key={cell.id}>
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</TableCell>
))}
</TableRow>
))}
</TableBody>
</Table>
);
}
7 changes: 5 additions & 2 deletions keep-ui/components/navbar/ConfigureLinks.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use client";

import { Subtitle } from "@tremor/react";
import { Badge, Subtitle } from "@tremor/react";
import { LinkWithIcon } from "components/LinkWithIcon";
import { VscDebugDisconnect } from "react-icons/vsc";
import { MdOutlineEngineering } from "react-icons/md";
Expand Down Expand Up @@ -33,7 +33,10 @@ export const ConfigureLinks = ({ session }: ConfigureLinksProps) => {
</li>
<li>
<LinkWithIcon href="/mapping" icon={RiMindMap}>
Mapping
Mapping{" "}
<Badge color="orange" size="xs">
Beta
</Badge>
</LinkWithIcon>
</li>
<li>
Expand Down
6 changes: 5 additions & 1 deletion keep-ui/utils/hooks/useMappingRules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ import useSWR, { SWRConfiguration } from "swr";
import { getApiURL } from "utils/apiUrl";
import { fetcher } from "utils/fetcher";

export const useMappings = (options: SWRConfiguration = {}) => {
export const useMappings = (
options: SWRConfiguration = {
revalidateOnFocus: false,
}
) => {
const apiUrl = getApiURL();
const { data: session } = useSession();

Expand Down
12 changes: 11 additions & 1 deletion keep/api/models/db/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,20 @@ class MappingRule(SQLModel, table=True):
) # max_length=204800)


class MappingRuleDto(BaseModel):
class MappRuleDtoBase(BaseModel):
name: str
description: Optional[str] = None
file_name: Optional[str] = None
priority: int = 0
matchers: list[str]


class MappingRuleDtoOut(MappRuleDtoBase, extra="ignore"):
id: int
created_by: Optional[str]
created_at: datetime
attributes: list[str] = []


class MappingRuleDtoIn(MappRuleDtoBase):
rows: list[dict]
24 changes: 19 additions & 5 deletions keep/api/routes/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from keep.api.core.db import get_session
from keep.api.core.dependencies import AuthenticatedEntity, AuthVerifier
from keep.api.models.db.mapping import MappingRule, MappingRuleDto
from keep.api.models.db.mapping import MappingRule, MappingRuleDtoIn, MappingRuleDtoOut

router = APIRouter()

Expand All @@ -16,20 +16,34 @@
def get_rules(
authenticated_entity: AuthenticatedEntity = Depends(AuthVerifier(["read:rules"])),
session: Session = Depends(get_session),
) -> list[MappingRule]:
) -> list[MappingRuleDtoOut]:
logger.info("Getting mapping rules")
rules: list[MappingRule] = (

Check warning on line 21 in keep/api/routes/mapping.py

View check run for this annotation

Codecov / codecov/patch

keep/api/routes/mapping.py#L20-L21

Added lines #L20 - L21 were not covered by tests
session.query(MappingRule)
.filter(MappingRule.tenant_id == authenticated_entity.tenant_id)
.all()
)
logger.info("Got mapping rules", extra={"rules_count": len(rules) if rules else 0})

Check warning on line 26 in keep/api/routes/mapping.py

View check run for this annotation

Codecov / codecov/patch

keep/api/routes/mapping.py#L26

Added line #L26 was not covered by tests
return rules

rules_dtos = []
if rules:
for rule in rules:
rule_dto = MappingRuleDtoOut(**rule.dict())
rule_dto.attributes = [

Check warning on line 32 in keep/api/routes/mapping.py

View check run for this annotation

Codecov / codecov/patch

keep/api/routes/mapping.py#L28-L32

Added lines #L28 - L32 were not covered by tests
key for key in rule.rows[0].keys() if key not in rule.matchers
]
rules_dtos.append(rule_dto)

Check warning on line 35 in keep/api/routes/mapping.py

View check run for this annotation

Codecov / codecov/patch

keep/api/routes/mapping.py#L35

Added line #L35 was not covered by tests

@router.post("", description="Create a new mapping rule")
return rules_dtos

Check warning on line 37 in keep/api/routes/mapping.py

View check run for this annotation

Codecov / codecov/patch

keep/api/routes/mapping.py#L37

Added line #L37 was not covered by tests


@router.post(
"",
description="Create a new mapping rule",
response_model_exclude={"rows", "tenant_id"},
)
def create_rule(
rule: MappingRuleDto,
rule: MappingRuleDtoIn,
authenticated_entity: AuthenticatedEntity = Depends(AuthVerifier(["write:rules"])),
session: Session = Depends(get_session),
) -> MappingRule:
Expand Down

0 comments on commit c354646

Please sign in to comment.