drawDB/src/components/table.jsx

502 lines
16 KiB
React
Raw Normal View History

2023-09-19 20:47:11 +08:00
import { React, useState } from "react";
2023-09-19 20:47:52 +08:00
import { sqlDataTypes } from "../data/data";
2023-09-19 20:47:18 +08:00
import {
IconEdit,
IconDelete,
IconPlus,
IconMinus,
2023-09-19 20:47:24 +08:00
} from "@douyinfe/semi-icons";
2023-09-19 20:47:28 +08:00
import {
Modal,
Form,
Checkbox,
Row,
Col,
Popover,
Tag,
2023-09-19 20:47:33 +08:00
Popconfirm,
Toast,
2023-09-19 20:47:28 +08:00
} from "@douyinfe/semi-ui";
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:11 +08:00
const [isHovered, setIsHovered] = useState(false);
2023-09-19 20:47:18 +08:00
const [hoveredField, setHoveredField] = useState(-1);
const [name, setName] = useState(props.tableData.name);
2023-09-19 20:47:24 +08:00
const [visible, setVisible] = useState(false);
2023-09-19 20:47:25 +08:00
const [editFieldVisible, setEditFieldVisible] = useState(-1);
2023-09-19 20:47:29 +08:00
const [field, setField] = useState({
name: "",
type: "",
default: "",
primary: false,
unique: false,
notNull: false,
increment: false,
2023-09-19 20:47:52 +08:00
comment: "",
2023-09-19 20:47:29 +08:00
});
2023-09-19 20:47:25 +08:00
const handleEditField = () => {
props.setTables((prev) => {
const updatedTables = [...prev];
updatedTables[props.id].fields[editFieldVisible] = { ...field };
return updatedTables;
2023-09-19 20:47:31 +08:00
});
2023-09-19 20:47:31 +08:00
setField({
name: "",
type: "",
default: "",
primary: false,
unique: false,
notNull: false,
increment: false,
2023-09-19 20:47:52 +08:00
comment: "",
2023-09-19 20:47:31 +08:00
});
2023-09-19 20:47:25 +08:00
setEditFieldVisible(-1);
};
2023-09-19 20:47:24 +08:00
const handleAddField = () => {
props.setTables((prev) => {
const updatedTables = [...prev];
updatedTables[props.id].fields = [
...updatedTables[props.id].fields,
{ ...field },
];
return updatedTables;
});
2023-09-19 20:47:30 +08:00
setField({
name: "",
type: "",
default: "",
primary: false,
unique: false,
notNull: false,
increment: false,
2023-09-19 20:47:52 +08:00
comment: "",
2023-09-19 20:47:30 +08:00
});
2023-09-19 20:47:24 +08:00
setVisible(false);
};
2023-09-19 20:47:51 +08:00
const height = props.tableData.fields.length * 36 + 40 + 4 + 36;
2023-09-19 20:47:17 +08:00
2023-09-19 20:47:31 +08:00
const onCheck = (checkedValues) => {
setField({
...field,
[checkedValues.target.value]: checkedValues.target.checked,
});
};
2023-09-19 20:47:06 +08:00
return (
<g>
2023-09-19 20:47:10 +08:00
<foreignObject
2023-09-19 20:47:06 +08:00
key={props.id}
x={props.tableData.x}
y={props.tableData.y}
width={240}
2023-09-19 20:47:17 +08:00
height={height}
2023-09-19 20:47:11 +08:00
style={{ cursor: "move" }}
2023-09-19 20:47:06 +08:00
onMouseDown={props.onMouseDown}
2023-09-19 20:47:11 +08:00
onMouseEnter={() => {
setIsHovered(true);
}}
onMouseLeave={() => {
setIsHovered(false);
2023-09-19 20:47:45 +08:00
props.setOnRect({
tableId: -1,
field: -2,
});
2023-09-19 20:47:11 +08:00
}}
2023-09-19 20:47:10 +08:00
>
2023-09-19 20:47:11 +08:00
<div
2023-09-19 20:47:17 +08:00
className={`border-2 ${
isHovered ? "border-sky-500" : "border-gray-500"
} bg-gray-300 select-none rounded-md`}
2023-09-19 20:47:11 +08:00
>
2023-09-19 20:47:54 +08:00
<div
style={{ backgroundColor: props.tableData.color }}
className={`p-3 font-bold text-slate-800 h-[40px] rounded-t-md flex justify-between items-center`}
>
2023-09-19 20:47:20 +08:00
{
2023-09-19 20:47:45 +08:00
<form
onSubmit={(e) => e.preventDefault()}
onMouseEnter={() =>
props.setOnRect({
tableId: props.id,
field: -1,
})
}
>
2023-09-19 20:47:20 +08:00
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
className={`p-1 select-text w-[100px] bg-gray-400 focus:bg-gray-200 ${
name < 1
? "ring-2 ring-red-600"
: "focus:ring-2 focus:ring-sky-500 "
}`}
/>
</form>
}
2023-09-19 20:47:18 +08:00
{isHovered && (
<div className="flex justify-end items-center">
2023-09-19 20:47:54 +08:00
<button className="btn bg-sky-800 text-white text-xs py-1 px-2 me-2 opacity-80">
2023-09-19 20:47:18 +08:00
<IconEdit />
</button>
<button
className="btn bg-green-600 text-white text-xs py-1 px-2 me-2 opacity-80"
2023-09-19 20:47:29 +08:00
onClick={(e) => setVisible(true)}
2023-09-19 20:47:18 +08:00
>
<IconPlus />
</button>
2023-09-19 20:47:33 +08:00
<Popconfirm
title="Are you sure you want to delete this table?"
content="This modification will be irreversible."
cancelText="Cancel"
okText="Delete"
onConfirm={() => {
Toast.success(`Table deleted!`);
props.onDelete(props.id);
}}
onCancel={() => {}}
2023-09-19 20:47:26 +08:00
>
2023-09-19 20:47:33 +08:00
<button className="btn bg-red-800 text-white text-xs py-1 px-2 opacity-80">
<IconDelete />
</button>
</Popconfirm>
2023-09-19 20:47:18 +08:00
</div>
)}
2023-09-19 20:47:17 +08:00
</div>
{props.tableData.fields.map((e, i) => {
2023-09-19 20:47:17 +08:00
return (
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={
<div>
<div className="flex justify-between items-center pb-2">
<p className="me-4 font-bold">{e.name}</p>
<p className="ms-4 text-slate-600">{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>
)}
<p className="text-slate-600">
<strong>Default :</strong>{" "}
{e.default === "" ? "Not set" : e.default}
</p>
2023-09-19 20:47:52 +08:00
<p className="text-slate-600">
<strong>Comment :</strong>{" "}
{e.comment === "" ? "Not comment" : e.comment}
2023-09-19 20:47:52 +08:00
</p>
2023-09-19 20:47:28 +08:00
</div>
}
position="right"
showArrow
>
<div
className={`${
i === props.tableData.fields.length - 1
? ""
: "border-b-2 border-gray-400"
2023-09-19 20:47:28 +08:00
} h-[36px] p-2 flex justify-between`}
onMouseEnter={() => {
setHoveredField(i);
2023-09-19 20:47:45 +08:00
props.setOnRect({
tableId: props.id,
field: i,
});
2023-09-19 20:47:28 +08:00
}}
onMouseLeave={() => {
setHoveredField(-1);
}}
>
<div
className={`${hoveredField === i ? "text-slate-600" : ""}`}
>
2023-09-19 20:47:35 +08:00
<button
className={`w-[10px] h-[10px] bg-green-600 rounded-full me-2`}
2023-09-19 20:47:35 +08:00
onMouseDown={(ev) => {
props.handleGripField(i);
2023-09-19 20:47:48 +08:00
props.setLine((prev) => ({
2023-09-19 20:47:48 +08:00
...prev,
startFieldId: i,
startTableId: props.id,
startX: props.tableData.x + 15,
startY: props.tableData.y + i * 36 + 40 + 19,
endX: props.tableData.x + 15,
endY: props.tableData.y + i * 36 + 40 + 19,
2023-09-19 20:47:48 +08:00
}));
2023-09-19 20:47:35 +08:00
}}
></button>
2023-09-19 20:47:34 +08:00
{e.name}
</div>
2023-09-19 20:47:28 +08:00
<div className="text-slate-600">
{hoveredField === i ? (
<div>
<button
className="btn bg-sky-800 text-white text-xs py-1 px-2 me-2 opacity-80"
2023-09-19 20:47:31 +08:00
onClick={(ev) => {
setEditFieldVisible(i);
setField({ ...e });
}}
2023-09-19 20:47:28 +08:00
>
<IconEdit />
</button>
<button
className="btn bg-red-800 text-white text-xs py-1 px-2 opacity-80"
onClick={(ev) => {
props.setTables((prev) => {
const updatedTables = [...prev];
const updatedFields = [
...updatedTables[props.id].fields,
];
updatedFields.splice(i, 1);
updatedTables[props.id].fields = [
...updatedFields,
];
return updatedTables;
});
2023-09-19 20:47:28 +08:00
}}
>
<IconMinus />
</button>
</div>
) : (
e.type
)}
</div>
2023-09-19 20:47:18 +08:00
</div>
2023-09-19 20:47:28 +08:00
</Popover>
2023-09-19 20:47:17 +08:00
);
})}
2023-09-19 20:47:51 +08:00
<div className="h-[36px] p-2">
2023-09-19 20:47:52 +08:00
{props.tableData.comment === ""
? "No comment"
: props.tableData.comment}
2023-09-19 20:47:51 +08:00
</div>
2023-09-19 20:47:10 +08:00
</div>
2023-09-19 20:47:08 +08:00
</foreignObject>
2023-09-19 20:47:34 +08:00
2023-09-19 20:47:24 +08:00
<Modal
title="Add new field"
visible={visible}
onOk={handleAddField}
2023-09-19 20:47:32 +08:00
onCancel={() => setVisible(false)}
2023-09-19 20:47:24 +08:00
centered
closeOnEsc={true}
okText="Add"
cancelText="Cancel"
>
2023-09-19 20:47:29 +08:00
<Form
labelPosition="left"
labelAlign="right"
onValueChange={(v) => setField({ ...field, ...v })}
>
2023-09-19 20:47:24 +08:00
<Row>
<Col span={11}>
<Form.Input field="name" label="Name" trigger="blur" />
2023-09-19 20:47:25 +08:00
</Col>
<Col span={2}></Col>
<Col span={11}>
<Form.Input field="default" label="Default" trigger="blur" />
</Col>
</Row>
<Row>
<Col span={24}>
<Form.Select
field="type"
label="Type"
className="w-full"
2023-09-19 20:47:26 +08:00
filter
2023-09-19 20:47:25 +08:00
optionList={sqlDataTypes.map((value, index) => {
return {
label: value,
2023-09-19 20:47:29 +08:00
value: value,
2023-09-19 20:47:25 +08:00
};
})}
></Form.Select>
2023-09-19 20:47:52 +08:00
<Form.Input field="comment" label="Comment" className="w-full" />
2023-09-19 20:47:25 +08:00
<div className="flex justify-around mt-2">
2023-09-19 20:47:29 +08:00
<Checkbox
value="primary"
onChange={() =>
setField({ ...field, primary: !field.primary })
}
>
Primary
</Checkbox>
<Checkbox
value="unique"
onChange={() => setField({ ...field, unique: !field.unique })}
>
Unique
</Checkbox>
<Checkbox
value="not null"
onChange={() =>
setField({ ...field, notNull: !field.notNull })
}
>
Not null
</Checkbox>
<Checkbox
value="increment"
onChange={() =>
setField({ ...field, increment: !field.increment })
}
>
Increment
</Checkbox>
2023-09-19 20:47:25 +08:00
</div>
</Col>
</Row>
</Form>
</Modal>
<Modal
title={`Edit field ${
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].name
: ""
2023-09-19 20:47:25 +08:00
}`}
visible={editFieldVisible !== -1}
onOk={handleEditField}
2023-09-19 20:47:31 +08:00
onCancel={() => setEditFieldVisible(-1)}
2023-09-19 20:47:25 +08:00
centered
closeOnEsc={true}
okText="Edit"
cancelText="Cancel"
>
2023-09-19 20:47:31 +08:00
<Form
labelPosition="left"
labelAlign="right"
onValueChange={(v) => setField({ ...field, ...v })}
>
2023-09-19 20:47:25 +08:00
<Row>
<Col span={11}>
2023-09-19 20:47:29 +08:00
<Form.Input
field="name"
label="Name"
trigger="blur"
2023-09-19 20:47:31 +08:00
initValue={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].name
: ""
2023-09-19 20:47:31 +08:00
}
2023-09-19 20:47:29 +08:00
/>
2023-09-19 20:47:24 +08:00
</Col>
<Col span={2}></Col>
<Col span={11}>
2023-09-19 20:47:29 +08:00
<Form.Input
field="default"
label="Default"
trigger="blur"
2023-09-19 20:47:31 +08:00
initValue={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].default
2023-09-19 20:47:31 +08:00
: ""
2023-09-19 20:47:29 +08:00
}
/>
2023-09-19 20:47:24 +08:00
</Col>
</Row>
<Row>
<Col span={24}>
<Form.Select
field="type"
label="Type"
className="w-full"
optionList={sqlDataTypes.map((value, index) => {
return {
label: value,
2023-09-19 20:47:31 +08:00
value: value,
2023-09-19 20:47:24 +08:00
};
})}
2023-09-19 20:47:32 +08:00
filter
2023-09-19 20:47:31 +08:00
initValue={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].type
: ""
2023-09-19 20:47:31 +08:00
}
2023-09-19 20:47:24 +08:00
></Form.Select>
2023-09-19 20:47:52 +08:00
<Form.Input
field="comment"
label="Comment"
trigger="blur"
initValue={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].comment
: ""
}
/>
2023-09-19 20:47:24 +08:00
<div className="flex justify-around mt-2">
2023-09-19 20:47:31 +08:00
<Checkbox
value="primary"
onChange={onCheck}
defaultChecked={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].primary
2023-09-19 20:47:31 +08:00
: undefined
}
>
Primary
</Checkbox>
<Checkbox
value="unique"
onChange={onCheck}
defaultChecked={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].unique
2023-09-19 20:47:31 +08:00
: undefined
}
>
Unique
</Checkbox>
<Checkbox
value="notNull"
onChange={onCheck}
defaultChecked={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].notNull
2023-09-19 20:47:31 +08:00
: undefined
}
>
Not null
</Checkbox>
<Checkbox
value="increment"
onChange={onCheck}
defaultChecked={
editFieldVisible !== -1
? props.tableData.fields[editFieldVisible].increment
2023-09-19 20:47:31 +08:00
: undefined
}
>
Increment
</Checkbox>
2023-09-19 20:47:24 +08:00
</div>
</Col>
</Row>
</Form>
</Modal>
2023-09-19 20:47:06 +08:00
</g>
);
2023-09-19 20:47:43 +08:00
}