mirror of
https://github.com/stackrender/stackrender.git
synced 2026-09-10 19:25:44 +00:00
149 lines
5.9 KiB
TypeScript
149 lines
5.9 KiB
TypeScript
import { Ref, useCallback, useEffect, useRef, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { RelationshipType } from "@/lib/schemas/relationship-schema";
|
|
import { useDatabase } from "@/providers/database-provider/database-provider";
|
|
import { useDiagram } from "@/providers/diagram-provider/diagram-provider";
|
|
import { useModal } from "@/providers/modal-provider/modal-provider";
|
|
import { Modals } from "@/providers/modal-provider/modal-contxet";
|
|
import { getDefaultRelationshipName } from "@/utils/relationship";
|
|
import EmptyList from "@/components/empty-list";
|
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { IconFilter2Up, IconPlus } from "@tabler/icons-react";
|
|
import { Accordion } from "@/components/ui/accordion";
|
|
import RelationshipAccordionItem from "./relationship-accordion-item/relationship-accordion-item";
|
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
import { Separator } from "@/components/ui/separator";
|
|
|
|
const RelationshipController: React.FC = ({ }) => {
|
|
|
|
|
|
const { open } = useModal();
|
|
const { database } = useDatabase();
|
|
const { relationships: allRelationships } = database || { relationships: [] };
|
|
const [relationships, setRelationships] = useState<RelationshipType[]>(allRelationships);
|
|
const nameRef: Ref<HTMLInputElement> = useRef<HTMLInputElement>(null);
|
|
const { t } = useTranslation();
|
|
const { focusedRelationshipId , setFocusedRelationshipId } = useDiagram();
|
|
|
|
useEffect(() => searchRelationships(), [allRelationships]);
|
|
|
|
useEffect(() => {
|
|
if (focusedRelationshipId) {
|
|
const accordionItem = document.getElementById(focusedRelationshipId)
|
|
if (accordionItem)
|
|
accordionItem?.scrollIntoView({
|
|
behavior: 'smooth', block: "nearest"
|
|
})
|
|
}
|
|
}, [focusedRelationshipId]);
|
|
|
|
const onOpen = useCallback(() => {
|
|
open(Modals.CREATE_RELATIONSHIP, {
|
|
onRlationshipCreated: (id: string) => setFocusedRelationshipId(id)
|
|
})
|
|
}, []);
|
|
|
|
const searchRelationships = useCallback(() => {
|
|
const keyword: string | undefined = nameRef.current?.value;
|
|
if (keyword !== undefined) {
|
|
|
|
setRelationships(() => {
|
|
return allRelationships.filter((relationship: RelationshipType) => {
|
|
if (relationship.name)
|
|
return relationship.name.toLowerCase().trim().includes(keyword.toLocaleLowerCase().trim());
|
|
else
|
|
return getDefaultRelationshipName(relationship).trim().toLocaleLowerCase().includes(
|
|
keyword.trim().toLocaleLowerCase()
|
|
)
|
|
})
|
|
})
|
|
}
|
|
}, [nameRef, allRelationships]);
|
|
|
|
const collapseAll = useCallback(() => {
|
|
setFocusedRelationshipId(undefined);
|
|
}, []);
|
|
|
|
return (
|
|
<div className="w-full h-full flex flex-col min-h-0">
|
|
<div className="flex items-center gap-2 p-3">
|
|
<Tooltip >
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant={"ghost"}
|
|
size={"icon"}
|
|
className="rounded-md h-8 w-8"
|
|
onClick={collapseAll}
|
|
>
|
|
<IconFilter2Up className="size-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
{t("db_controller.collapse")}
|
|
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
<Input
|
|
className="h-8 bg-secondary dark:bg-background"
|
|
placeholder={t("db_controller.filter")}
|
|
ref={nameRef}
|
|
type="text"
|
|
onKeyUp={searchRelationships}
|
|
/>
|
|
<Tooltip >
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant={"default"}
|
|
size={"icon"}
|
|
className="rounded-md h-8 w-8"
|
|
onClick={onOpen}
|
|
>
|
|
<IconPlus className="size-4 " />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>
|
|
{t("db_controller.add_relationship")}
|
|
</TooltipContent>
|
|
</Tooltip>
|
|
|
|
</div>
|
|
|
|
{
|
|
allRelationships.length > 0 &&
|
|
<ScrollArea className="flex-1 px-3 overflow-hidden">
|
|
<Accordion
|
|
type="single"
|
|
collapsible
|
|
className="w-full "
|
|
value={focusedRelationshipId}
|
|
onValueChange={setFocusedRelationshipId}
|
|
>
|
|
{relationships.map((relationship: RelationshipType) => (
|
|
<>
|
|
<RelationshipAccordionItem relationship={relationship} key={relationship.id} />
|
|
<Separator className="my-1" />
|
|
</>
|
|
))}
|
|
</Accordion>
|
|
</ScrollArea>
|
|
}
|
|
|
|
{
|
|
(allRelationships.length == 0) &&
|
|
<div className="px-3 h-full">
|
|
<EmptyList
|
|
title={t("db_controller.empty_list.no_relationships")}
|
|
description={t("db_controller.empty_list.no_relationships_description")}
|
|
/>
|
|
</div>
|
|
}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default RelationshipController
|
|
|
|
|