Add sidesheet for editing relationships
This commit is contained in:
parent
6cd0a691dc
commit
557ce72961
@ -87,6 +87,8 @@ export default function Canvas() {
|
|||||||
* @param {ObjectType[keyof ObjectType]} type
|
* @param {ObjectType[keyof ObjectType]} type
|
||||||
*/
|
*/
|
||||||
const handlePointerDownOnElement = (e, id, type) => {
|
const handlePointerDownOnElement = (e, id, type) => {
|
||||||
|
if (selectedElement.open && !layout.sidebar) return;
|
||||||
|
|
||||||
if (!e.isPrimary) return;
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
if (type === ObjectType.TABLE) {
|
if (type === ObjectType.TABLE) {
|
||||||
@ -138,6 +140,8 @@ export default function Canvas() {
|
|||||||
* @param {PointerEvent} e
|
* @param {PointerEvent} e
|
||||||
*/
|
*/
|
||||||
const handlePointerMove = (e) => {
|
const handlePointerMove = (e) => {
|
||||||
|
if (selectedElement.open && !layout.sidebar) return;
|
||||||
|
|
||||||
if (!e.isPrimary) return;
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
if (linking) {
|
if (linking) {
|
||||||
@ -226,6 +230,8 @@ export default function Canvas() {
|
|||||||
* @param {PointerEvent} e
|
* @param {PointerEvent} e
|
||||||
*/
|
*/
|
||||||
const handlePointerDown = (e) => {
|
const handlePointerDown = (e) => {
|
||||||
|
if (selectedElement.open && !layout.sidebar) return;
|
||||||
|
|
||||||
if (!e.isPrimary) return;
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
// don't pan if the sidesheet for editing a table is open
|
// don't pan if the sidesheet for editing a table is open
|
||||||
@ -309,6 +315,8 @@ export default function Canvas() {
|
|||||||
* @param {PointerEvent} e
|
* @param {PointerEvent} e
|
||||||
*/
|
*/
|
||||||
const handlePointerUp = (e) => {
|
const handlePointerUp = (e) => {
|
||||||
|
if (selectedElement.open && !layout.sidebar) return;
|
||||||
|
|
||||||
if (!e.isPrimary) return;
|
if (!e.isPrimary) return;
|
||||||
|
|
||||||
if (coordsDidUpdate(dragging.element)) {
|
if (coordsDidUpdate(dragging.element)) {
|
||||||
|
@ -3,6 +3,8 @@ import { Cardinality, ObjectType, Tab } from "../../data/constants";
|
|||||||
import { calcPath } from "../../utils/calcPath";
|
import { calcPath } from "../../utils/calcPath";
|
||||||
import { useDiagram, useSettings, useLayout, useSelect } from "../../hooks";
|
import { useDiagram, useSettings, useLayout, useSelect } from "../../hooks";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { SideSheet } from "@douyinfe/semi-ui";
|
||||||
|
import RelationshipInfo from "../EditorSidePanel/RelationshipsTab/RelationshipInfo";
|
||||||
|
|
||||||
export default function Relationship({ data }) {
|
export default function Relationship({ data }) {
|
||||||
const { settings } = useSettings();
|
const { settings } = useSettings();
|
||||||
@ -79,67 +81,90 @@ export default function Relationship({ data }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g className="select-none group" onDoubleClick={edit}>
|
<>
|
||||||
<path
|
<g className="select-none group" onDoubleClick={edit}>
|
||||||
ref={pathRef}
|
<path
|
||||||
d={calcPath(
|
ref={pathRef}
|
||||||
{
|
d={calcPath(
|
||||||
...data,
|
{
|
||||||
startTable: {
|
...data,
|
||||||
x: tables[data.startTableId].x,
|
startTable: {
|
||||||
y: tables[data.startTableId].y,
|
x: tables[data.startTableId].x,
|
||||||
|
y: tables[data.startTableId].y,
|
||||||
|
},
|
||||||
|
endTable: {
|
||||||
|
x: tables[data.endTableId].x,
|
||||||
|
y: tables[data.endTableId].y,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
endTable: {
|
settings.tableWidth,
|
||||||
x: tables[data.endTableId].x,
|
)}
|
||||||
y: tables[data.endTableId].y,
|
stroke="gray"
|
||||||
},
|
className="group-hover:stroke-sky-700"
|
||||||
},
|
fill="none"
|
||||||
settings.tableWidth,
|
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"
|
</g>
|
||||||
className="group-hover:stroke-sky-700"
|
<SideSheet
|
||||||
fill="none"
|
title={t("edit")}
|
||||||
strokeWidth={2}
|
size="small"
|
||||||
cursor="pointer"
|
visible={
|
||||||
/>
|
selectedElement.element === ObjectType.RELATIONSHIP &&
|
||||||
{pathRef.current && settings.showCardinality && (
|
selectedElement.id === data.id &&
|
||||||
<>
|
selectedElement.open &&
|
||||||
<circle
|
!layout.sidebar
|
||||||
cx={cardinalityStartX}
|
}
|
||||||
cy={cardinalityStartY}
|
onCancel={() => {
|
||||||
r="12"
|
setSelectedElement((prev) => ({
|
||||||
fill="grey"
|
...prev,
|
||||||
className="group-hover:fill-sky-700"
|
open: false,
|
||||||
/>
|
}));
|
||||||
<text
|
}}
|
||||||
x={cardinalityStartX}
|
style={{ paddingBottom: "16px" }}
|
||||||
y={cardinalityStartY}
|
>
|
||||||
fill="white"
|
<div className="sidesheet-theme">
|
||||||
strokeWidth="0.5"
|
<RelationshipInfo data={data} />
|
||||||
textAnchor="middle"
|
</div>
|
||||||
alignmentBaseline="middle"
|
</SideSheet>
|
||||||
>
|
</>
|
||||||
{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>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,4 @@
|
|||||||
import {
|
import { Row, Col, Select, Button, Popover, Table } from "@douyinfe/semi-ui";
|
||||||
Collapse,
|
|
||||||
Row,
|
|
||||||
Col,
|
|
||||||
Select,
|
|
||||||
Button,
|
|
||||||
Popover,
|
|
||||||
Table,
|
|
||||||
} from "@douyinfe/semi-ui";
|
|
||||||
import {
|
import {
|
||||||
IconDeleteStroked,
|
IconDeleteStroked,
|
||||||
IconLoopTextStroked,
|
IconLoopTextStroked,
|
||||||
@ -128,110 +120,100 @@ export default function RelationshipInfo({ data }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={`scroll_ref_${data.id}`}>
|
<>
|
||||||
<Collapse.Panel
|
<div className="flex justify-between items-center mb-3">
|
||||||
header={
|
<div className="me-3">
|
||||||
<div className="overflow-hidden text-ellipsis whitespace-nowrap">
|
<span className="font-semibold">{t("primary")}: </span>
|
||||||
{data.name}
|
{tables[data.endTableId].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>
|
</div>
|
||||||
<div className="font-semibold my-1">{t("cardinality")}:</div>
|
<div className="mx-1">
|
||||||
<Select
|
<span className="font-semibold">{t("foreign")}: </span>
|
||||||
optionList={Object.values(Cardinality).map((v) => ({
|
{tables[data.startTableId].name}
|
||||||
label: t(v),
|
</div>
|
||||||
value: v,
|
<div className="ms-1">
|
||||||
}))}
|
<Popover
|
||||||
value={data.cardinality}
|
content={
|
||||||
className="w-full"
|
<div className="p-2 popover-theme">
|
||||||
onChange={changeCardinality}
|
<Table
|
||||||
/>
|
columns={columns}
|
||||||
<Row gutter={6} className="my-3">
|
dataSource={[
|
||||||
<Col span={12}>
|
{
|
||||||
<div className="font-semibold">{t("on_update")}: </div>
|
key: "1",
|
||||||
<Select
|
foreign: `${tables[data.startTableId].name}(${
|
||||||
optionList={Object.values(Constraint).map((v) => ({
|
tables[data.startTableId].fields[data.startFieldId].name
|
||||||
label: v,
|
})`,
|
||||||
value: v,
|
primary: `${tables[data.endTableId].name}(${
|
||||||
}))}
|
tables[data.endTableId].fields[data.endFieldId].name
|
||||||
value={data.updateConstraint}
|
})`,
|
||||||
className="w-full"
|
},
|
||||||
onChange={(value) => changeConstraint("update", value)}
|
]}
|
||||||
/>
|
pagination={false}
|
||||||
</Col>
|
size="small"
|
||||||
<Col span={12}>
|
bordered
|
||||||
<div className="font-semibold">{t("on_delete")}: </div>
|
/>
|
||||||
<Select
|
<div className="mt-2">
|
||||||
optionList={Object.values(Constraint).map((v) => ({
|
<Button
|
||||||
label: v,
|
icon={<IconLoopTextStroked />}
|
||||||
value: v,
|
block
|
||||||
}))}
|
onClick={swapKeys}
|
||||||
value={data.deleteConstraint}
|
>
|
||||||
className="w-full"
|
{t("swap")}
|
||||||
onChange={(value) => changeConstraint("delete", value)}
|
</Button>
|
||||||
/>
|
</div>
|
||||||
</Col>
|
</div>
|
||||||
</Row>
|
}
|
||||||
<Button
|
trigger="click"
|
||||||
icon={<IconDeleteStroked />}
|
position="rightTop"
|
||||||
block
|
showArrow
|
||||||
type="danger"
|
>
|
||||||
onClick={() => deleteRelationship(data.id)}
|
<Button icon={<IconMore />} type="tertiary" />
|
||||||
>
|
</Popover>
|
||||||
{t("delete")}
|
</div>
|
||||||
</Button>
|
</div>
|
||||||
</Collapse.Panel>
|
<div className="font-semibold my-1">{t("cardinality")}:</div>
|
||||||
</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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,34 +14,47 @@ export default function RelationshipsTab() {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SearchBar />
|
<SearchBar />
|
||||||
<Collapse
|
{relationships.length <= 0 ? (
|
||||||
activeKey={
|
<Empty
|
||||||
selectedElement.open &&
|
title={t("no_relationships")}
|
||||||
selectedElement.element === ObjectType.RELATIONSHIP
|
text={t("no_relationships_text")}
|
||||||
? `${selectedElement.id}`
|
/>
|
||||||
: ""
|
) : (
|
||||||
}
|
<Collapse
|
||||||
keepDOM
|
activeKey={
|
||||||
lazyRender
|
selectedElement.open &&
|
||||||
onChange={(k) =>
|
selectedElement.element === ObjectType.RELATIONSHIP
|
||||||
setSelectedElement((prev) => ({
|
? `${selectedElement.id}`
|
||||||
...prev,
|
: ""
|
||||||
open: true,
|
}
|
||||||
id: parseInt(k),
|
keepDOM
|
||||||
element: ObjectType.RELATIONSHIP,
|
lazyRender
|
||||||
}))
|
onChange={(k) =>
|
||||||
}
|
setSelectedElement((prev) => ({
|
||||||
accordion
|
...prev,
|
||||||
>
|
open: true,
|
||||||
{relationships.length <= 0 ? (
|
id: parseInt(k),
|
||||||
<Empty
|
element: ObjectType.RELATIONSHIP,
|
||||||
title={t("no_relationships")}
|
}))
|
||||||
text={t("no_relationships_text")}
|
}
|
||||||
/>
|
accordion
|
||||||
) : (
|
>
|
||||||
relationships.map((r) => <RelationshipInfo key={r.id} data={r} />)
|
{relationships.map((r) => (
|
||||||
)}
|
<div id={`scroll_ref_${r.id}`} key={"relationship_" + r.id}>
|
||||||
</Collapse>
|
<Collapse.Panel
|
||||||
|
header={
|
||||||
|
<div className="overflow-hidden text-ellipsis whitespace-nowrap">
|
||||||
|
{r.name}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
itemKey={`${r.id}`}
|
||||||
|
>
|
||||||
|
<RelationshipInfo data={r} />
|
||||||
|
</Collapse.Panel>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Collapse>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ function Relationship({ relationship, tables }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g className="select-none" onClick={() => console.log(pathRef.current)}>
|
<g className="select-none">
|
||||||
<path
|
<path
|
||||||
ref={pathRef}
|
ref={pathRef}
|
||||||
d={calcPath({
|
d={calcPath({
|
||||||
|
Loading…
Reference in New Issue
Block a user