Add sidesheet for editing relationships

This commit is contained in:
1ilit 2024-09-07 23:52:03 +04:00
parent 6cd0a691dc
commit 557ce72961
5 changed files with 230 additions and 202 deletions

View File

@ -87,6 +87,8 @@ export default function Canvas() {
* @param {ObjectType[keyof ObjectType]} type
*/
const handlePointerDownOnElement = (e, id, type) => {
if (selectedElement.open && !layout.sidebar) return;
if (!e.isPrimary) return;
if (type === ObjectType.TABLE) {
@ -138,6 +140,8 @@ export default function Canvas() {
* @param {PointerEvent} e
*/
const handlePointerMove = (e) => {
if (selectedElement.open && !layout.sidebar) return;
if (!e.isPrimary) return;
if (linking) {
@ -226,6 +230,8 @@ export default function Canvas() {
* @param {PointerEvent} e
*/
const handlePointerDown = (e) => {
if (selectedElement.open && !layout.sidebar) return;
if (!e.isPrimary) return;
// don't pan if the sidesheet for editing a table is open
@ -309,6 +315,8 @@ export default function Canvas() {
* @param {PointerEvent} e
*/
const handlePointerUp = (e) => {
if (selectedElement.open && !layout.sidebar) return;
if (!e.isPrimary) return;
if (coordsDidUpdate(dragging.element)) {

View File

@ -3,6 +3,8 @@ import { Cardinality, ObjectType, Tab } from "../../data/constants";
import { calcPath } from "../../utils/calcPath";
import { useDiagram, useSettings, useLayout, useSelect } from "../../hooks";
import { useTranslation } from "react-i18next";
import { SideSheet } from "@douyinfe/semi-ui";
import RelationshipInfo from "../EditorSidePanel/RelationshipsTab/RelationshipInfo";
export default function Relationship({ data }) {
const { settings } = useSettings();
@ -79,67 +81,90 @@ export default function Relationship({ data }) {
};
return (
<g className="select-none group" onDoubleClick={edit}>
<path
ref={pathRef}
d={calcPath(
{
...data,
startTable: {
x: tables[data.startTableId].x,
y: tables[data.startTableId].y,
<>
<g className="select-none group" onDoubleClick={edit}>
<path
ref={pathRef}
d={calcPath(
{
...data,
startTable: {
x: tables[data.startTableId].x,
y: tables[data.startTableId].y,
},
endTable: {
x: tables[data.endTableId].x,
y: tables[data.endTableId].y,
},
},
endTable: {
x: tables[data.endTableId].x,
y: tables[data.endTableId].y,
},
},
settings.tableWidth,
settings.tableWidth,
)}
stroke="gray"
className="group-hover:stroke-sky-700"
fill="none"
strokeWidth={2}
cursor="pointer"
/>
{pathRef.current && settings.showCardinality && (
<>
<circle
cx={cardinalityStartX}
cy={cardinalityStartY}
r="12"
fill="grey"
className="group-hover:fill-sky-700"
/>
<text
x={cardinalityStartX}
y={cardinalityStartY}
fill="white"
strokeWidth="0.5"
textAnchor="middle"
alignmentBaseline="middle"
>
{cardinalityStart}
</text>
<circle
cx={cardinalityEndX}
cy={cardinalityEndY}
r="12"
fill="grey"
className="group-hover:fill-sky-700"
/>
<text
x={cardinalityEndX}
y={cardinalityEndY}
fill="white"
strokeWidth="0.5"
textAnchor="middle"
alignmentBaseline="middle"
>
{cardinalityEnd}
</text>
</>
)}
stroke="gray"
className="group-hover:stroke-sky-700"
fill="none"
strokeWidth={2}
cursor="pointer"
/>
{pathRef.current && settings.showCardinality && (
<>
<circle
cx={cardinalityStartX}
cy={cardinalityStartY}
r="12"
fill="grey"
className="group-hover:fill-sky-700"
/>
<text
x={cardinalityStartX}
y={cardinalityStartY}
fill="white"
strokeWidth="0.5"
textAnchor="middle"
alignmentBaseline="middle"
>
{cardinalityStart}
</text>
<circle
cx={cardinalityEndX}
cy={cardinalityEndY}
r="12"
fill="grey"
className="group-hover:fill-sky-700"
/>
<text
x={cardinalityEndX}
y={cardinalityEndY}
fill="white"
strokeWidth="0.5"
textAnchor="middle"
alignmentBaseline="middle"
>
{cardinalityEnd}
</text>
</>
)}
</g>
</g>
<SideSheet
title={t("edit")}
size="small"
visible={
selectedElement.element === ObjectType.RELATIONSHIP &&
selectedElement.id === data.id &&
selectedElement.open &&
!layout.sidebar
}
onCancel={() => {
setSelectedElement((prev) => ({
...prev,
open: false,
}));
}}
style={{ paddingBottom: "16px" }}
>
<div className="sidesheet-theme">
<RelationshipInfo data={data} />
</div>
</SideSheet>
</>
);
}

View File

@ -1,12 +1,4 @@
import {
Collapse,
Row,
Col,
Select,
Button,
Popover,
Table,
} from "@douyinfe/semi-ui";
import { Row, Col, Select, Button, Popover, Table } from "@douyinfe/semi-ui";
import {
IconDeleteStroked,
IconLoopTextStroked,
@ -128,110 +120,100 @@ export default function RelationshipInfo({ data }) {
};
return (
<div id={`scroll_ref_${data.id}`}>
<Collapse.Panel
header={
<div className="overflow-hidden text-ellipsis whitespace-nowrap">
{data.name}
</div>
}
itemKey={`${data.id}`}
>
<div className="flex justify-between items-center mb-3">
<div className="me-3">
<span className="font-semibold">{t("primary")}: </span>
{tables[data.endTableId].name}
</div>
<div className="mx-1">
<span className="font-semibold">{t("foreign")}: </span>
{tables[data.startTableId].name}
</div>
<div className="ms-1">
<Popover
content={
<div className="p-2 popover-theme">
<Table
columns={columns}
dataSource={[
{
key: "1",
foreign: `${tables[data.startTableId].name}(${
tables[data.startTableId].fields[data.startFieldId]
.name
})`,
primary: `${tables[data.endTableId].name}(${
tables[data.endTableId].fields[data.endFieldId].name
})`,
},
]}
pagination={false}
size="small"
bordered
/>
<div className="mt-2">
<Button
icon={<IconLoopTextStroked />}
block
onClick={swapKeys}
>
{t("swap")}
</Button>
</div>
</div>
}
trigger="click"
position="rightTop"
showArrow
>
<Button icon={<IconMore />} type="tertiary" />
</Popover>
</div>
<>
<div className="flex justify-between items-center mb-3">
<div className="me-3">
<span className="font-semibold">{t("primary")}: </span>
{tables[data.endTableId].name}
</div>
<div className="font-semibold my-1">{t("cardinality")}:</div>
<Select
optionList={Object.values(Cardinality).map((v) => ({
label: t(v),
value: v,
}))}
value={data.cardinality}
className="w-full"
onChange={changeCardinality}
/>
<Row gutter={6} className="my-3">
<Col span={12}>
<div className="font-semibold">{t("on_update")}: </div>
<Select
optionList={Object.values(Constraint).map((v) => ({
label: v,
value: v,
}))}
value={data.updateConstraint}
className="w-full"
onChange={(value) => changeConstraint("update", value)}
/>
</Col>
<Col span={12}>
<div className="font-semibold">{t("on_delete")}: </div>
<Select
optionList={Object.values(Constraint).map((v) => ({
label: v,
value: v,
}))}
value={data.deleteConstraint}
className="w-full"
onChange={(value) => changeConstraint("delete", value)}
/>
</Col>
</Row>
<Button
icon={<IconDeleteStroked />}
block
type="danger"
onClick={() => deleteRelationship(data.id)}
>
{t("delete")}
</Button>
</Collapse.Panel>
</div>
<div className="mx-1">
<span className="font-semibold">{t("foreign")}: </span>
{tables[data.startTableId].name}
</div>
<div className="ms-1">
<Popover
content={
<div className="p-2 popover-theme">
<Table
columns={columns}
dataSource={[
{
key: "1",
foreign: `${tables[data.startTableId].name}(${
tables[data.startTableId].fields[data.startFieldId].name
})`,
primary: `${tables[data.endTableId].name}(${
tables[data.endTableId].fields[data.endFieldId].name
})`,
},
]}
pagination={false}
size="small"
bordered
/>
<div className="mt-2">
<Button
icon={<IconLoopTextStroked />}
block
onClick={swapKeys}
>
{t("swap")}
</Button>
</div>
</div>
}
trigger="click"
position="rightTop"
showArrow
>
<Button icon={<IconMore />} type="tertiary" />
</Popover>
</div>
</div>
<div className="font-semibold my-1">{t("cardinality")}:</div>
<Select
optionList={Object.values(Cardinality).map((v) => ({
label: t(v),
value: v,
}))}
value={data.cardinality}
className="w-full"
onChange={changeCardinality}
/>
<Row gutter={6} className="my-3">
<Col span={12}>
<div className="font-semibold">{t("on_update")}: </div>
<Select
optionList={Object.values(Constraint).map((v) => ({
label: v,
value: v,
}))}
value={data.updateConstraint}
className="w-full"
onChange={(value) => changeConstraint("update", value)}
/>
</Col>
<Col span={12}>
<div className="font-semibold">{t("on_delete")}: </div>
<Select
optionList={Object.values(Constraint).map((v) => ({
label: v,
value: v,
}))}
value={data.deleteConstraint}
className="w-full"
onChange={(value) => changeConstraint("delete", value)}
/>
</Col>
</Row>
<Button
icon={<IconDeleteStroked />}
block
type="danger"
onClick={() => deleteRelationship(data.id)}
>
{t("delete")}
</Button>
</>
);
}

View File

@ -14,34 +14,47 @@ export default function RelationshipsTab() {
return (
<>
<SearchBar />
<Collapse
activeKey={
selectedElement.open &&
selectedElement.element === ObjectType.RELATIONSHIP
? `${selectedElement.id}`
: ""
}
keepDOM
lazyRender
onChange={(k) =>
setSelectedElement((prev) => ({
...prev,
open: true,
id: parseInt(k),
element: ObjectType.RELATIONSHIP,
}))
}
accordion
>
{relationships.length <= 0 ? (
<Empty
title={t("no_relationships")}
text={t("no_relationships_text")}
/>
) : (
relationships.map((r) => <RelationshipInfo key={r.id} data={r} />)
)}
</Collapse>
{relationships.length <= 0 ? (
<Empty
title={t("no_relationships")}
text={t("no_relationships_text")}
/>
) : (
<Collapse
activeKey={
selectedElement.open &&
selectedElement.element === ObjectType.RELATIONSHIP
? `${selectedElement.id}`
: ""
}
keepDOM
lazyRender
onChange={(k) =>
setSelectedElement((prev) => ({
...prev,
open: true,
id: parseInt(k),
element: ObjectType.RELATIONSHIP,
}))
}
accordion
>
{relationships.map((r) => (
<div id={`scroll_ref_${r.id}`} key={"relationship_" + r.id}>
<Collapse.Panel
header={
<div className="overflow-hidden text-ellipsis whitespace-nowrap">
{r.name}
</div>
}
itemKey={`${r.id}`}
>
<RelationshipInfo data={r} />
</Collapse.Panel>
</div>
))}
</Collapse>
)}
</>
);
}

View File

@ -117,7 +117,7 @@ function Relationship({ relationship, tables }) {
}
return (
<g className="select-none" onClick={() => console.log(pathRef.current)}>
<g className="select-none">
<path
ref={pathRef}
d={calcPath({