import { React, useContext, useState } from "react"; import { Action, ObjectType, defaultTableTheme, sqlDataTypes, tableThemes, } from "../data/data"; import { Collapse, Row, Col, Input, TextArea, Button, Card, TagInput, Popover, Checkbox, Select, AutoComplete, Toast, Empty, } from "@douyinfe/semi-ui"; import { IconMore, IconKeyStroked, IconDeleteStroked, IconCheckboxTick, IconPlus, IconSearch, } from "@douyinfe/semi-icons"; import { IllustrationNoContent, IllustrationNoContentDark, } from "@douyinfe/semi-illustrations"; import { SelectContext, TableContext, UndoRedoContext } from "../pages/editor"; export default function TableOverview(props) { const [indexActiveKey, setIndexActiveKey] = useState(""); const [value, setValue] = useState(""); const { tables, addTable, deleteTable, updateField, updateTable } = useContext(TableContext); const { setUndoStack, setRedoStack } = useContext(UndoRedoContext); const { selectedElement, setSelectedElement } = useContext(SelectContext); const [editField, setEditField] = useState({}); const [filteredResult, setFilteredResult] = useState( tables.map((t) => { return t.name; }) ); const handleStringSearch = (value) => { setFilteredResult( tables .map((t) => { return t.name; }) .filter((i) => i.includes(value)) ); }; return ( <> } placeholder="Search..." onSearch={(v) => handleStringSearch(v)} onChange={(v) => setValue(v)} onSelect={(v) => { const { id } = tables.find((t) => t.name === v); setSelectedElement({ element: ObjectType.TABLE, id: id, openDialogue: false, openCollapse: true, }); document .getElementById(`scroll_table_${id}`) .scrollIntoView({ behavior: "smooth" }); }} className="w-full" /> } block onClick={() => addTable(true)}> Add table setSelectedElement({ element: ObjectType.TABLE, id: parseInt(k), openDialogue: false, openCollapse: true, }) } accordion > {tables.length <= 0 ? ( } darkModeImage={ } title="No tables" description="Start building your diagram!" /> ) : ( tables.map((t, i) => ( {t.name}} itemKey={`${t.id}`}> {t.fields.map((f, j) => ( updateField(i, j, { name: value })} onFocus={(e) => setEditField({ name: e.target.value })} onBlur={(e) => { if (e.target.value === editField.name) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: editField, redo: { name: e.target.value }, }, ]); setRedoStack([]); }} /> { return { label: value, value: value, }; })} filter value={f.type} placeholder="Type" onChange={(value) => { if (value === f.type) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: { type: f.type }, redo: { type: value }, }, ]); setRedoStack([]); const incr = f.increment && (value === "INT" || value === "BIGINT" || value === "SMALLINT"); updateField( i, j, value === "ENUM" ? { type: value, enumValues: [], increment: incr } : { type: value, length: value === "VARCHAR" ? 255 : "n/a", increment: incr, } ); }} > { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: { notNull: f.notNull }, redo: { notNull: !f.notNull }, }, ]); setRedoStack([]); updateField(i, j, { notNull: !f.notNull }); }} > ? { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: { primary: f.primary }, redo: { primary: !f.primary }, }, ]); setRedoStack([]); updateField(i, j, { primary: !f.primary }); }} icon={} > Default value updateField(i, j, { default: value }) } onFocus={(e) => setEditField({ default: e.target.value }) } onBlur={(e) => { if (e.target.value === editField.default) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: editField, redo: { default: e.target.value }, }, ]); setRedoStack([]); }} /> {f.type === "ENUM" && ( <> Enum values updateField(i, j, { enumValues: v }) } onFocus={(e) => setEditField({ enumValues: f.enumValues }) } onBlur={(e) => { if ( JSON.stringify(editField.enumValues) === JSON.stringify(f.enumValues) ) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: editField, redo: { enumValues: f.enumValues }, }, ]); setRedoStack([]); }} /> > )} {f.type === "VARCHAR" && ( <> Length updateField(i, j, { length: value }) } onFocus={(e) => setEditField({ length: e.target.value }) } onBlur={(e) => { if (e.target.value === editField.length) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: editField, redo: { length: e.target.value }, }, ]); setRedoStack([]); }} /> > )} Check Expression updateField(i, j, { check: value }) } onFocus={(e) => setEditField({ check: e.target.value }) } onBlur={(e) => { if (e.target.value === editField.check) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: editField, redo: { check: e.target.value }, }, ]); setRedoStack([]); }} /> Unique { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: { [checkedValues.target.value]: !checkedValues.target.checked, }, redo: { [checkedValues.target.value]: checkedValues.target.checked, }, }, ]); setRedoStack([]); updateField(i, j, { [checkedValues.target.value]: checkedValues.target.checked, }); }} > Autoincrement { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: { [checkedValues.target.value]: !checkedValues.target.checked, }, redo: { [checkedValues.target.value]: checkedValues.target.checked, }, }, ]); setRedoStack([]); updateField(i, j, { [checkedValues.target.value]: checkedValues.target.checked, }); }} > Comment updateField(i, j, { comment: value }) } onFocus={(e) => setEditField({ comment: e.target.value }) } onBlur={(e) => { if (e.target.value === editField.comment) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field", tid: i, fid: j, undo: editField, redo: { comment: e.target.value }, }, ]); setRedoStack([]); }} /> } type="danger" block onClick={() => { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field_delete", tid: t.id, data: f, }, ]); setRedoStack([]); updateTable(i, { fields: t.fields .filter((field) => field.id !== j) .map((e, i) => ({ ...e, id: i })), }); }} > Delete field } trigger="click" position="right" showArrow > }> ))} {t.indices.length > 0 && ( setIndexActiveKey(itemKey)} accordion > {t.indices.map((idx, k) => ( ({ value: e.name, label: e.name, }))} className="w-full" value={idx.fields} onChange={(value) => { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "index", tid: i, iid: k, undo: { fields: [...idx.fields], name: `${idx.fields.join("_")}_index`, }, redo: { fields: [...value], name: `${value.join("_")}_index`, }, }, ]); setRedoStack([]); updateTable(i, { indices: t.indices.map((index) => index.id === k ? { ...index, fields: [...value], name: `${value.join("_")}_index`, } : index ), }); }} /> } type="danger" block onClick={() => { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "index_delete", tid: t.id, data: idx, }, ]); setRedoStack([]); updateTable(i, { indices: t.indices .filter((e) => e.id !== k) .map((e, j) => ({ ...e, id: j, })), }); }} > Delete } trigger="click" position="rightTop" showArrow > } type="tertiary" style={{ marginLeft: "12px" }} > ))} )} updateTable(i, { comment: value }, false) } onFocus={(e) => setEditField({ comment: e.target.value }) } onBlur={(e) => { if (e.target.value === editField.comment) return; setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "comment", tid: i, undo: editField, redo: { comment: e.target.value }, }, ]); setRedoStack([]); }} /> Theme { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "self", tid: i, undo: { color: t.color }, redo: { color: defaultTableTheme }, }, ]); setRedoStack([]); updateTable(i, { color: defaultTableTheme }); }} > Clear {tableThemes .slice(0, Math.ceil(tableThemes.length / 2)) .map((c) => ( { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "self", tid: i, undo: { color: t.color }, redo: { color: c }, }, ]); setRedoStack([]); updateTable(i, { color: c }); }} > {t.color === c ? ( ) : ( )} ))} {tableThemes .slice(Math.ceil(tableThemes.length / 2)) .map((c) => ( { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "self", tid: i, undo: { color: t.color }, redo: { color: c }, }, ]); setRedoStack([]); updateTable(i, { color: c }); }} > ))} } trigger="click" position="bottomLeft" showArrow > { setIndexActiveKey("1"); setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "index_add", tid: t.id, }, ]); setRedoStack([]); updateTable(i, { indices: [ ...t.indices, { id: t.indices.length, name: `index_${t.indices.length}`, fields: [], }, ], }); }} > Add index { setUndoStack((prev) => [ ...prev, { action: Action.EDIT, element: ObjectType.TABLE, component: "field_add", tid: t.id, }, ]); setRedoStack([]); updateTable(i, { fields: [ ...t.fields, { name: "", type: "", default: "", check: "", primary: false, length: "n/a", unique: false, notNull: false, increment: false, comment: "", id: t.fields.length, }, ], }); }} block > Add field } type="danger" onClick={() => { Toast.success(`Table deleted!`); deleteTable(i); }} > )) )} > ); }