add search table functionality

This commit is contained in:
1ilit 2023-09-19 15:48:09 +03:00
parent a49e90991b
commit 519b9d0a27
3 changed files with 503 additions and 444 deletions

View File

@ -105,44 +105,6 @@ export default function EditorPanel(props) {
add area add area
</button> </button>
<br /> <br />
<button
onClick={() => {
const newTable = {
id: props.tables.length,
name: `table_${props.tables.length}`,
x: 0,
y: 0,
fields: [
{
name: "id",
type: "UUID",
default: "",
check: "",
primary: true,
unique: true,
notNull: true,
increment: true,
comment: "",
},
],
comment: "",
indices: [],
color: defaultTableTheme,
};
props.setTables((prev) => {
const updatedTables = [...prev, newTable];
return updatedTables;
});
props.setCode((prev) =>
prev === ""
? `CREATE TABLE \`${newTable.name}\`;`
: `${prev}\n\nCREATE TABLE \`${newTable.name}\`;`
);
}}
>
add
</button>
<br />
<button <button
onClick={() => { onClick={() => {
const blob = new Blob([props.code], { const blob = new Blob([props.code], {

View File

@ -11,6 +11,7 @@ import {
Popover, Popover,
Checkbox, Checkbox,
Select, Select,
AutoComplete,
} from "@douyinfe/semi-ui"; } from "@douyinfe/semi-ui";
import { import {
IconMore, IconMore,
@ -18,10 +19,13 @@ import {
IconColorPalette, IconColorPalette,
IconDeleteStroked, IconDeleteStroked,
IconCheckboxTick, IconCheckboxTick,
IconPlus,
IconSearch,
} from "@douyinfe/semi-icons"; } from "@douyinfe/semi-icons";
export default function TableOverview(props) { export default function TableOverview(props) {
const [indexActiveKey, setIndexActiveKey] = useState(""); const [indexActiveKey, setIndexActiveKey] = useState("");
const [indexActiveKeyTable, setIndexActiveKeyTable] = useState("");
const updateColor = (id, c) => { const updateColor = (id, c) => {
const updatedTables = [...props.tables]; const updatedTables = [...props.tables];
@ -29,266 +33,274 @@ export default function TableOverview(props) {
props.setTables(updatedTables); props.setTables(updatedTables);
}; };
const [value, setValue] = useState("");
const [filteredResult, setFilteredResult] = useState(
props.tables.map((t) => {
return t.name;
})
);
const handleStringSearch = (value) => {
setFilteredResult(
props.tables
.map((t) => {
return t.name;
})
.filter((i) => i.includes(value))
);
};
const handleChange = (value) => {
setValue(value);
};
return ( return (
<Collapse> <>
{props.tables.map((t, i) => ( <div className="p-2">
<Collapse.Panel <Row gutter={6}>
key={i} <Col span={16}>
header={ <AutoComplete
<div> data={filteredResult}
<Input defaultValue={t.name} borderless /> value={value}
</div> showClear
} prefix={<IconSearch />}
itemKey={`${i}`} placeholder="Search..."
> emptyContent={<div className="p-3">No tables found</div>}
{t.fields.map((f, j) => ( onSearch={(v) => handleStringSearch(v)}
<Form onChange={(v) => handleChange(v)}
key={j} onSelect={(v) => {
onChange={(value) => { const { id, name } = props.tables.find((t) => t.name === v);
const updatedTables = [...props.tables]; setIndexActiveKeyTable(`${id}`);
updatedTables[i].fields = updatedTables[i].fields.map( document
(field, index) => .getElementById(`${name}_scroll_id`)
index === j ? { ...field, ...value.values } : field .scrollIntoView({ behavior: "smooth" });
); }}
props.setTables(updatedTables); className="w-full"
/>
</Col>
<Col span={8}>
<Button
icon={<IconPlus />}
block
onClick={() => {
const newTable = {
id: props.tables.length,
name: `table_${props.tables.length}`,
x: 0,
y: 0,
fields: [
{
name: "id",
type: "UUID",
default: "",
check: "",
primary: true,
unique: true,
notNull: true,
increment: true,
comment: "",
},
],
comment: "",
indices: [],
color: defaultTableTheme,
};
props.setTables((prev) => {
const updatedTables = [...prev, newTable];
return updatedTables;
});
}} }}
> >
<Row Add table
type="flex" </Button>
justify="start" </Col>
align="middle" </Row>
gutter={6} </div>
className="hover:bg-slate-100" <Collapse
> activeKey={indexActiveKeyTable}
<Col span={7}> onChange={(i) => setIndexActiveKeyTable(i)}
<Form.Input >
field="name" {props.tables.map((t, i) => (
noLabel={true} <div id={`${t.name}_scroll_id`} key={i}>
initValue={f.name} <Collapse.Panel
className="m-0" header={
placeholder="Name" <div>
/> <Input defaultValue={t.name} borderless />
</Col> </div>
<Col span={8}> }
<Form.Select itemKey={`${t.id}`}
className="w-full"
field="type"
noLabel={true}
optionList={sqlDataTypes.map((value, index) => {
return {
label: value,
value: value,
};
})}
filter
initValue={f.type}
></Form.Select>
</Col>
<Col span={3}>
<Button
type={f.notNull ? "primary" : "tertiary"}
title="Nullable"
theme={f.notNull ? "solid" : "light"}
onClick={() => {
const updatedTables = [...props.tables];
updatedTables[i].fields = updatedTables[i].fields.map(
(field, index) =>
index === j
? { ...field, notNull: !f.notNull }
: field
);
props.setTables(updatedTables);
}}
>
?
</Button>
</Col>
<Col span={3}>
<Button
type={f.primary ? "primary" : "tertiary"}
title="Nullable"
theme={f.primary ? "solid" : "light"}
onClick={() => {
const updatedTables = [...props.tables];
updatedTables[i].fields = updatedTables[i].fields.map(
(field, index) =>
index === j
? { ...field, primary: !f.primary }
: field
);
props.setTables(updatedTables);
}}
icon={<IconKeyStroked />}
></Button>
</Col>
<Col span={3}>
<Popover
content={
<div className="px-1">
<Form
onChange={(value) => {
const updatedTables = [...props.tables];
updatedTables[i] = {
...updatedTables[i],
fields: updatedTables[i].fields.map(
(field, index) =>
index === j
? { ...field, ...value.values }
: field
),
};
props.setTables(updatedTables);
}}
>
<Form.Input
field="default"
label="Default"
initValue={f.default}
trigger="blur"
placeholder="Set default"
/>
<Form.Input
field="check"
label="Check Expression"
trigger="blur"
placeholder="Set constraint"
initValue={f.check}
/>
<div className="flex justify-between items-center my-3">
<label htmlFor="unique" className="font-medium">
Unique
</label>
<Checkbox
value="unique"
defaultChecked={f.unique}
onChange={(checkedValues) => {
const updatedTables = [...props.tables];
updatedTables[i].fields = updatedTables[
i
].fields.map((field, index) =>
index === j
? {
...field,
[checkedValues.target.value]:
checkedValues.target.checked,
}
: field
);
props.setTables(updatedTables);
}}
></Checkbox>
</div>
<div className="flex justify-between items-center my-3">
<label htmlFor="increment" className="font-medium">
Autoincrement
</label>
<Checkbox
value="increment"
defaultChecked={f.increment}
onChange={(checkedValues) => {
const updatedTables = [...props.tables];
updatedTables[i].fields = updatedTables[
i
].fields.map((field, index) =>
index === j
? {
...field,
[checkedValues.target.value]:
checkedValues.target.checked,
}
: field
);
props.setTables(updatedTables);
}}
></Checkbox>
</div>
<Form.TextArea
field="comment"
label="Comment"
placeholder="Add comment"
initValue={f.comment}
autosize
rows={2}
/>
</Form>
<Button
icon={<IconDeleteStroked />}
type="danger"
block
onClick={() => {
const updatedTables = [...props.tables];
const updatedFields = [...t.fields];
updatedFields.splice(j, 1);
updatedTables[i] = {
...t,
fields: [...updatedFields],
};
props.setTables(updatedTables);
}}
>
Delete
</Button>
</div>
}
trigger="click"
position="rightTop"
showArrow
>
<Button type="tertiary" icon={<IconMore />}></Button>
</Popover>
</Col>
</Row>
</Form>
))}
{t.indices.length > 0 && (
<Card
bodyStyle={{ padding: "4px" }}
style={{ marginTop: "12px", marginBottom: "12px" }}
headerLine={false}
> >
<Collapse {t.fields.map((f, j) => (
activeKey={indexActiveKey} <Form
onChange={(itemKey) => setIndexActiveKey(itemKey)} key={j}
> onChange={(value) => {
<Collapse.Panel header="Indices" itemKey="1"> const updatedTables = [...props.tables];
{t.indices.map((idx, k) => ( updatedTables[i].fields = updatedTables[i].fields.map(
<div (field, index) =>
className="flex justify-between items-center mb-2" index === j ? { ...field, ...value.values } : field
key={k} );
> props.setTables(updatedTables);
<Select }}
placeholder="Select fields" >
multiple <Row
optionList={t.fields.map((e) => ({ type="flex"
value: e.name, justify="start"
label: e.name, align="middle"
}))} gutter={6}
className="hover:bg-slate-100"
>
<Col span={7}>
<Form.Input
field="name"
noLabel={true}
initValue={f.name}
className="m-0"
placeholder="Name"
/>
</Col>
<Col span={8}>
<Form.Select
className="w-full" className="w-full"
defaultValue={idx.fields} field="type"
onChange={(value) => { noLabel={true}
optionList={sqlDataTypes.map((value, index) => {
return {
label: value,
value: value,
};
})}
filter
initValue={f.type}
></Form.Select>
</Col>
<Col span={3}>
<Button
type={f.notNull ? "primary" : "tertiary"}
title="Nullable"
theme={f.notNull ? "solid" : "light"}
onClick={() => {
const updatedTables = [...props.tables]; const updatedTables = [...props.tables];
const updatedIndices = [...t.indices]; updatedTables[i].fields = updatedTables[i].fields.map(
updatedIndices[k] = { (field, index) =>
name: `${value.join("_")}_index`, index === j
fields: [...value], ? { ...field, notNull: !f.notNull }
}; : field
updatedTables[i] = { );
...t,
indices: [...updatedIndices],
};
props.setTables(updatedTables); props.setTables(updatedTables);
}} }}
/> >
?
</Button>
</Col>
<Col span={3}>
<Button
type={f.primary ? "primary" : "tertiary"}
title="Nullable"
theme={f.primary ? "solid" : "light"}
onClick={() => {
const updatedTables = [...props.tables];
updatedTables[i].fields = updatedTables[i].fields.map(
(field, index) =>
index === j
? { ...field, primary: !f.primary }
: field
);
props.setTables(updatedTables);
}}
icon={<IconKeyStroked />}
></Button>
</Col>
<Col span={3}>
<Popover <Popover
content={ content={
<div className="px-1"> <div className="px-1">
<Form> <Form
onChange={(value) => {
const updatedTables = [...props.tables];
updatedTables[i] = {
...updatedTables[i],
fields: updatedTables[i].fields.map(
(field, index) =>
index === j
? { ...field, ...value.values }
: field
),
};
props.setTables(updatedTables);
}}
>
<Form.Input <Form.Input
field="name" field="default"
label="Name" label="Default"
initValue={idx.name} initValue={f.default}
trigger="blur" trigger="blur"
placeholder="Index name" placeholder="Set default"
/>
<Form.Input
field="check"
label="Check Expression"
trigger="blur"
placeholder="Set constraint"
initValue={f.check}
/>
<div className="flex justify-between items-center my-3">
<label htmlFor="unique" className="font-medium">
Unique
</label>
<Checkbox
value="unique"
defaultChecked={f.unique}
onChange={(checkedValues) => {
const updatedTables = [...props.tables];
updatedTables[i].fields = updatedTables[
i
].fields.map((field, index) =>
index === j
? {
...field,
[checkedValues.target.value]:
checkedValues.target.checked,
}
: field
);
props.setTables(updatedTables);
}}
></Checkbox>
</div>
<div className="flex justify-between items-center my-3">
<label
htmlFor="increment"
className="font-medium"
>
Autoincrement
</label>
<Checkbox
value="increment"
defaultChecked={f.increment}
onChange={(checkedValues) => {
const updatedTables = [...props.tables];
updatedTables[i].fields = updatedTables[
i
].fields.map((field, index) =>
index === j
? {
...field,
[checkedValues.target.value]:
checkedValues.target.checked,
}
: field
);
props.setTables(updatedTables);
}}
></Checkbox>
</div>
<Form.TextArea
field="comment"
label="Comment"
placeholder="Add comment"
initValue={f.comment}
autosize
rows={2}
/> />
</Form> </Form>
<Button <Button
@ -297,11 +309,11 @@ export default function TableOverview(props) {
block block
onClick={() => { onClick={() => {
const updatedTables = [...props.tables]; const updatedTables = [...props.tables];
const updatedIndices = [...t.indices]; const updatedFields = [...t.fields];
updatedIndices.splice(k, 1); updatedFields.splice(j, 1);
updatedTables[i] = { updatedTables[i] = {
...t, ...t,
indices: [...updatedIndices], fields: [...updatedFields],
}; };
props.setTables(updatedTables); props.setTables(updatedTables);
}} }}
@ -314,165 +326,254 @@ export default function TableOverview(props) {
position="rightTop" position="rightTop"
showArrow showArrow
> >
<Button <Button type="tertiary" icon={<IconMore />}></Button>
icon={<IconMore />}
type="tertiary"
style={{ marginLeft: "12px" }}
></Button>
</Popover> </Popover>
</div> </Col>
))} </Row>
</Collapse.Panel> </Form>
</Collapse> ))}
</Card> {t.indices.length > 0 && (
)} <Card
<Card bodyStyle={{ padding: "4px" }}
bodyStyle={{ padding: "4px" }} style={{ marginTop: "12px", marginBottom: "12px" }}
style={{ marginTop: "12px", marginBottom: "12px" }} headerLine={false}
headerLine={false}
>
<Collapse>
<Collapse.Panel header="Comment" itemKey="1">
<Form
onChange={(value) => {
const updatedTables = [...props.tables];
updatedTables[i] = {
...t,
...value.values,
};
props.setTables(updatedTables);
}}
> >
<Form.TextArea <Collapse
field="comment" activeKey={indexActiveKey}
noLabel={true} onChange={(itemKey) => setIndexActiveKey(itemKey)}
showClear >
onClear={() => { <Collapse.Panel header="Indices" itemKey="1">
{t.indices.map((idx, k) => (
<div
className="flex justify-between items-center mb-2"
key={k}
>
<Select
placeholder="Select fields"
multiple
optionList={t.fields.map((e) => ({
value: e.name,
label: e.name,
}))}
className="w-full"
defaultValue={idx.fields}
onChange={(value) => {
const updatedTables = [...props.tables];
const updatedIndices = [...t.indices];
updatedIndices[k] = {
name: `${value.join("_")}_index`,
fields: [...value],
};
updatedTables[i] = {
...t,
indices: [...updatedIndices],
};
props.setTables(updatedTables);
}}
/>
<Popover
content={
<div className="px-1">
<Form>
<Form.Input
field="name"
label="Name"
initValue={idx.name}
trigger="blur"
placeholder="Index name"
/>
</Form>
<Button
icon={<IconDeleteStroked />}
type="danger"
block
onClick={() => {
const updatedTables = [...props.tables];
const updatedIndices = [...t.indices];
updatedIndices.splice(k, 1);
updatedTables[i] = {
...t,
indices: [...updatedIndices],
};
props.setTables(updatedTables);
}}
>
Delete
</Button>
</div>
}
trigger="click"
position="rightTop"
showArrow
>
<Button
icon={<IconMore />}
type="tertiary"
style={{ marginLeft: "12px" }}
></Button>
</Popover>
</div>
))}
</Collapse.Panel>
</Collapse>
</Card>
)}
<Card
bodyStyle={{ padding: "4px" }}
style={{ marginTop: "12px", marginBottom: "12px" }}
headerLine={false}
>
<Collapse>
<Collapse.Panel header="Comment" itemKey="1">
<Form
onChange={(value) => {
const updatedTables = [...props.tables];
updatedTables[i] = {
...t,
...value.values,
};
props.setTables(updatedTables);
}}
>
<Form.TextArea
field="comment"
noLabel={true}
showClear
onClear={() => {
const updatedTables = [...props.tables];
updatedTables[i] = {
...t,
comment: "",
};
props.setTables(updatedTables);
}}
initValue={t.comment}
autosize
placeholder="Add comment"
rows={1}
/>
</Form>
</Collapse.Panel>
</Collapse>
</Card>
<Row gutter={6} className="mt-2">
<Col span={8}>
<Popover
content={
<div>
<div className="flex justify-between items-center p-2">
<div className="font-medium">Theme</div>
<Button
type="tertiary"
size="small"
onClick={() => updateColor(i, defaultTableTheme)}
>
Clear
</Button>
</div>
<hr />
<div className="py-3">
<div>
{tableThemes
.slice(0, Math.ceil(tableThemes.length / 2))
.map((c) => (
<button
key={c}
style={{ backgroundColor: c }}
className="p-3 rounded-full mx-1"
onClick={() => updateColor(i, c)}
>
{t.color === c ? (
<IconCheckboxTick
style={{ color: "white" }}
/>
) : (
<IconCheckboxTick style={{ color: c }} />
)}
</button>
))}
</div>
<div className="mt-3">
{tableThemes
.slice(Math.ceil(tableThemes.length / 2))
.map((c) => (
<button
key={c}
style={{ backgroundColor: c }}
className="p-3 rounded-full mx-1"
onClick={() => updateColor(i, c)}
>
{t.color === c ? (
<IconCheckboxTick
style={{ color: "white" }}
/>
) : (
<IconCheckboxTick style={{ color: c }} />
)}
</button>
))}
</div>
</div>
</div>
}
trigger="click"
position="bottomLeft"
showArrow
>
<Button
type="tertiary"
icon={<IconColorPalette />}
></Button>
</Popover>
</Col>
<Col span={8}>
<Button
block
onClick={() => {
setIndexActiveKey("1");
const updatedTables = [...props.tables]; const updatedTables = [...props.tables];
updatedTables[i] = { updatedTables[i] = {
...t, ...t,
comment: "", indices: [
...t.indices,
{ name: `index_${t.indices.length}`, fields: [] },
],
}; };
props.setTables(updatedTables); props.setTables(updatedTables);
}} }}
initValue={t.comment} >
autosize Add index
placeholder="Add comment" </Button>
rows={1} </Col>
/> <Col span={8}>
</Form> <Button
</Collapse.Panel> onClick={() => {
</Collapse> const updatedTables = [...props.tables];
</Card> updatedTables[i].fields = [
<Row gutter={6} className="mt-2"> ...updatedTables[i].fields,
<Col span={8}> {
<Popover name: "",
content={ type: "",
<div> default: "",
<div className="flex justify-between items-center p-2"> primary: false,
<div className="font-medium">Theme</div> unique: false,
<Button notNull: false,
type="tertiary" increment: false,
size="small" comment: "",
onClick={() => updateColor(i, defaultTableTheme)} },
> ];
Clear props.setTables(updatedTables);
</Button> }}
</div> block
<hr /> >
<div className="py-3"> Add field
<div> </Button>
{tableThemes </Col>
.slice(0, Math.ceil(tableThemes.length / 2)) </Row>
.map((c) => ( </Collapse.Panel>
<button </div>
key={c} ))}
style={{ backgroundColor: c }} </Collapse>
className="p-3 rounded-full mx-1" </>
onClick={() => updateColor(i, c)}
>
{t.color === c ? (
<IconCheckboxTick style={{ color: "white" }} />
) : (
<IconCheckboxTick style={{ color: c }} />
)}
</button>
))}
</div>
<div className="mt-3">
{tableThemes
.slice(Math.ceil(tableThemes.length / 2))
.map((c) => (
<button
key={c}
style={{ backgroundColor: c }}
className="p-3 rounded-full mx-1"
onClick={() => updateColor(i, c)}
>
{t.color === c ? (
<IconCheckboxTick style={{ color: "white" }} />
) : (
<IconCheckboxTick style={{ color: c }} />
)}
</button>
))}
</div>
</div>
</div>
}
trigger="click"
position="bottomLeft"
showArrow
>
<Button type="tertiary" icon={<IconColorPalette />}></Button>
</Popover>
</Col>
<Col span={8}>
<Button
block
onClick={() => {
setIndexActiveKey("1");
const updatedTables = [...props.tables];
updatedTables[i] = {
...t,
indices: [
...t.indices,
{ name: `index_${t.indices.length}`, fields: [] },
],
};
props.setTables(updatedTables);
}}
>
Add index
</Button>
</Col>
<Col span={8}>
<Button
onClick={() => {
const updatedTables = [...props.tables];
updatedTables[i].fields = [
...updatedTables[i].fields,
{
name: "",
type: "",
default: "",
primary: false,
unique: false,
notNull: false,
increment: false,
comment: "",
},
];
props.setTables(updatedTables);
}}
block
>
Add field
</Button>
</Col>
</Row>
</Collapse.Panel>
))}
</Collapse>
); );
} }

View File

@ -6,10 +6,6 @@
outline: none !important; outline: none !important;
} }
body {
overflow: hidden;
}
.bg-blue { .bg-blue {
background-color: #124559; background-color: #124559;
} }