drawDB/src/components/EditorCanvas/Table.jsx

345 lines
11 KiB
React
Raw Normal View History

2024-03-14 02:39:16 +08:00
import { useState } from "react";
2023-09-19 20:48:57 +08:00
import {
Tab,
2023-09-19 20:50:16 +08:00
ObjectType,
2024-04-06 14:51:38 +08:00
tableFieldHeight,
tableHeaderHeight,
tableColorStripHeight,
2024-04-02 00:44:50 +08:00
} from "../../data/constants";
2023-09-19 20:48:53 +08:00
import {
IconEdit,
IconMore,
IconMinus,
IconDeleteStroked,
IconKeyStroked,
} from "@douyinfe/semi-icons";
2024-04-06 14:51:38 +08:00
import { Popover, Tag, Button, Toast, SideSheet } from "@douyinfe/semi-ui";
import { useLayout, useSettings, useTables, useSelect } from "../../hooks";
import TableInfo from "../EditorSidePanel/TablesTab/TableInfo";
2023-09-19 20:47:06 +08:00
2023-09-19 20:47:43 +08:00
export default function Table(props) {
2023-09-19 20:47:18 +08:00
const [hoveredField, setHoveredField] = useState(-1);
2024-04-06 09:58:42 +08:00
const {
2024-04-06 14:51:38 +08:00
tableData,
onMouseDown,
setHoveredTable,
handleGripField,
setLinkingLine,
} = props;
const { layout } = useLayout();
const { deleteTable, deleteField } = useTables();
2024-03-10 04:39:46 +08:00
const { settings } = useSettings();
const { selectedElement, setSelectedElement } = useSelect();
2023-09-19 20:47:17 +08:00
2024-04-06 14:51:38 +08:00
const height =
tableData.fields.length * tableFieldHeight + tableHeaderHeight + 7;
2024-04-10 17:15:48 +08:00
const openEditor = () => {
if (!layout.sidebar) {
setSelectedElement((prev) => ({
...prev,
element: ObjectType.TABLE,
id: tableData.id,
open: true,
}));
} else {
setSelectedElement((prev) => ({
...prev,
currentTab: Tab.TABLES,
element: ObjectType.TABLE,
id: tableData.id,
open: true,
}));
if (selectedElement.currentTab !== Tab.TABLES) return;
document
.getElementById(`scroll_table_${tableData.id}`)
.scrollIntoView({ behavior: "smooth" });
}
};
2023-09-19 20:47:31 +08:00
2023-09-19 20:47:06 +08:00
return (
2023-09-19 20:50:16 +08:00
<>
2023-09-19 20:47:10 +08:00
<foreignObject
2024-04-06 14:51:38 +08:00
key={tableData.id}
x={tableData.x}
y={tableData.y}
width={settings.tableWidth}
2023-09-19 20:47:17 +08:00
height={height}
2024-04-02 08:38:58 +08:00
className="group drop-shadow-lg rounded-md cursor-move"
2024-04-06 14:51:38 +08:00
onMouseDown={onMouseDown}
2023-09-19 20:47:10 +08:00
>
2023-09-19 20:47:11 +08:00
<div
2024-04-10 17:15:48 +08:00
onDoubleClick={openEditor}
2024-04-02 08:38:58 +08:00
className={`border-2 hover:border-dashed hover:border-blue-500
select-none rounded-lg w-full ${
settings.mode === "light"
? "bg-zinc-100 text-zinc-800"
: "bg-zinc-800 text-zinc-200"
} ${
selectedElement.id === tableData.id &&
selectedElement.element === ObjectType.TABLE
? "border-solid border-blue-500"
: "border-zinc-500"
}`}
2023-09-19 20:47:11 +08:00
>
2023-09-19 20:47:54 +08:00
<div
2024-04-02 01:57:13 +08:00
className="h-[10px] w-full rounded-t-md"
2024-04-06 14:51:38 +08:00
style={{ backgroundColor: tableData.color }}
2023-09-19 20:48:44 +08:00
/>
2023-09-19 20:51:08 +08:00
<div
2024-04-02 01:57:13 +08:00
className={`overflow-hidden font-bold h-[40px] flex justify-between items-center border-b border-gray-400 ${
settings.mode === "light" ? "bg-zinc-200" : "bg-zinc-900"
}`}
2023-09-19 20:51:08 +08:00
>
<div className=" px-3 overflow-hidden text-ellipsis whitespace-nowrap">
2024-04-06 14:51:38 +08:00
{tableData.name}
2023-09-19 20:50:49 +08:00
</div>
<div className="hidden group-hover:block">
<div className="flex justify-end items-center mx-2">
2023-09-19 20:48:44 +08:00
<Button
icon={<IconEdit />}
2023-09-19 20:48:44 +08:00
size="small"
theme="solid"
2023-09-19 20:48:44 +08:00
style={{
backgroundColor: "#2f68ad",
2023-09-19 20:48:44 +08:00
opacity: "0.7",
marginRight: "6px",
}}
2024-04-10 17:15:48 +08:00
onClick={openEditor}
2024-03-16 08:23:10 +08:00
/>
<Popover
key={tableData.key}
content={
<div className="popover-theme">
<div className="mb-2">
<strong>Comment :</strong>{" "}
2024-04-06 14:51:38 +08:00
{tableData.comment === "" ? (
"No comment"
) : (
2024-04-06 14:51:38 +08:00
<div>{tableData.comment}</div>
)}
</div>
<div>
<strong
className={`${
2024-04-06 14:51:38 +08:00
tableData.indices.length === 0 ? "" : "block"
}`}
>
Indices :
</strong>{" "}
2024-04-06 14:51:38 +08:00
{tableData.indices.length === 0 ? (
"No indices"
) : (
<div>
2024-04-06 14:51:38 +08:00
{tableData.indices.map((index, k) => (
<div
key={k}
className={`flex items-center my-1 px-2 py-1 rounded ${
settings.mode === "light"
? "bg-gray-100"
: "bg-zinc-800"
}`}
>
<i className="fa-solid fa-thumbtack me-2 mt-1 text-slate-500"></i>
<div>
{index.fields.map((f) => (
<Tag color="blue" key={f} className="me-1">
{f}
</Tag>
))}
</div>
</div>
))}
</div>
)}
</div>
<Button
icon={<IconDeleteStroked />}
type="danger"
block
style={{ marginTop: "8px" }}
onClick={() => {
Toast.success(`Table deleted!`);
2024-04-06 14:51:38 +08:00
deleteTable(tableData.id);
}}
>
Delete table
</Button>
</div>
}
position="rightTop"
showArrow
trigger="click"
style={{ width: "200px", wordBreak: "break-word" }}
>
<Button
icon={<IconMore />}
type="tertiary"
size="small"
style={{
opacity: "0.7",
backgroundColor: "grey",
color: "white",
}}
/>
</Popover>
</div>
2024-04-02 08:38:58 +08:00
</div>
2023-09-19 20:47:17 +08:00
</div>
2024-04-06 14:51:38 +08:00
{tableData.fields.map((e, i) => {
2023-09-19 20:49:16 +08:00
return settings.showFieldSummary ? (
2023-09-19 20:47:28 +08:00
<Popover
2023-09-19 20:47:24 +08:00
key={i}
2023-09-19 20:47:28 +08:00
content={
2023-09-19 20:51:08 +08:00
<div className="popover-theme">
2023-09-19 20:47:28 +08:00
<div className="flex justify-between items-center pb-2">
<p className="me-4 font-bold">{e.name}</p>
2023-09-19 20:51:08 +08:00
<p className="ms-4">{e.type}</p>
2023-09-19 20:47:18 +08:00
</div>
2023-09-19 20:47:28 +08:00
<hr />
{e.primary && (
<Tag color="blue" className="me-2 my-2">
Primary
</Tag>
)}
{e.unique && (
<Tag color="amber" className="me-2 my-2">
Unique
</Tag>
)}
{e.notNull && (
<Tag color="purple" className="me-2 my-2">
Not null
</Tag>
)}
{e.increment && (
<Tag color="green" className="me-2 my-2">
2023-09-19 20:47:29 +08:00
Increment
2023-09-19 20:47:28 +08:00
</Tag>
)}
2023-09-19 20:51:08 +08:00
<p>
2023-09-19 20:47:28 +08:00
<strong>Default :</strong>{" "}
{e.default === "" ? "Not set" : e.default}
</p>
<p>
<strong>Comment:</strong>{" "}
{e.comment === "" ? (
"Not comment"
) : (
<div>{e.comment}</div>
)}
</p>
2023-09-19 20:51:08 +08:00
</div>
2023-09-19 20:47:28 +08:00
}
position="right"
showArrow
style={{ width: "200px", wordBreak: "break-word" }}
2023-09-19 20:47:28 +08:00
>
2023-09-19 20:49:16 +08:00
{field(e, i)}
2023-09-19 20:47:28 +08:00
</Popover>
2023-09-19 20:49:16 +08:00
) : (
field(e, i)
2023-09-19 20:47:17 +08:00
);
})}
2023-09-19 20:47:10 +08:00
</div>
2023-09-19 20:47:08 +08:00
</foreignObject>
2023-09-19 20:48:46 +08:00
<SideSheet
2023-09-19 20:48:53 +08:00
title="Edit table"
2023-09-19 20:50:16 +08:00
size="small"
visible={
selectedElement.element === ObjectType.TABLE &&
2024-04-06 14:51:38 +08:00
selectedElement.id === tableData.id &&
2024-03-14 02:39:16 +08:00
selectedElement.open &&
!layout.sidebar
}
2023-09-19 20:50:28 +08:00
onCancel={() =>
setSelectedElement((prev) => ({
...prev,
2024-03-14 02:39:16 +08:00
open: !prev.open,
2023-09-19 20:50:28 +08:00
}))
}
2023-09-19 20:48:53 +08:00
style={{ paddingBottom: "16px" }}
2023-09-19 20:48:46 +08:00
>
<div className="sidesheet-theme">
<TableInfo data={tableData} />
</div>
2023-09-19 20:48:46 +08:00
</SideSheet>
2023-09-19 20:50:16 +08:00
</>
2023-09-19 20:47:06 +08:00
);
2023-09-19 20:49:16 +08:00
function field(fieldData, index) {
return (
<div
className={`${
index === tableData.fields.length - 1
? ""
: "border-b border-gray-400"
2024-04-06 14:51:38 +08:00
} group h-[36px] px-2 py-1 flex justify-between items-center gap-1 w-full overflow-hidden`}
2023-09-19 20:49:16 +08:00
onMouseEnter={() => {
setHoveredField(index);
2024-04-06 14:51:38 +08:00
setHoveredTable({
tableId: tableData.id,
2023-09-19 20:49:16 +08:00
field: index,
});
}}
onMouseLeave={() => {
setHoveredField(-1);
}}
>
2024-04-02 01:31:24 +08:00
<div
className={`${
hoveredField === index ? "text-zinc-400" : ""
} flex items-center gap-2 overflow-hidden`}
>
2023-09-19 20:49:16 +08:00
<button
2024-04-02 01:31:24 +08:00
className="flex-shrink-0 w-[10px] h-[10px] bg-[#2f68ad] opacity-80 z-50 rounded-full"
2023-12-16 11:39:13 +08:00
onMouseDown={() => {
2024-04-06 14:51:38 +08:00
handleGripField(index);
setLinkingLine((prev) => ({
2023-09-19 20:49:16 +08:00
...prev,
startFieldId: index,
2024-04-06 14:51:38 +08:00
startTableId: tableData.id,
startX: tableData.x + 15,
startY:
tableData.y +
index * tableFieldHeight +
tableHeaderHeight +
tableColorStripHeight +
12,
2024-04-06 14:51:38 +08:00
endX: tableData.x + 15,
endY:
tableData.y +
index * tableFieldHeight +
tableHeaderHeight +
tableColorStripHeight +
12,
2023-09-19 20:49:16 +08:00
}));
}}
2024-03-16 08:23:10 +08:00
/>
2024-04-02 01:31:24 +08:00
<span className="overflow-hidden text-ellipsis whitespace-nowrap">
{fieldData.name}
</span>
2023-09-19 20:49:16 +08:00
</div>
2023-09-19 20:51:08 +08:00
<div className="text-zinc-400">
2023-09-19 20:49:16 +08:00
{hoveredField === index ? (
<Button
theme="solid"
size="small"
style={{
opacity: "0.7",
backgroundColor: "#d42020",
}}
icon={<IconMinus />}
2024-04-06 14:51:38 +08:00
onClick={() => deleteField(fieldData, tableData.id)}
2024-03-16 08:23:10 +08:00
/>
2023-09-19 20:49:16 +08:00
) : (
2024-04-02 05:22:07 +08:00
<div className="flex gap-1 items-center">
{fieldData.primary && <IconKeyStroked />}
<span>{fieldData.type}</span>
</div>
2023-09-19 20:49:16 +08:00
)}
</div>
</div>
);
}
2023-09-19 20:47:43 +08:00
}