added chat

This commit is contained in:
1ilit 2023-09-19 15:50:57 +03:00
parent be0ec46e4b
commit 274c434206
8 changed files with 209 additions and 59 deletions

129
package-lock.json generated
View File

@ -8,7 +8,6 @@
"name": "frontend", "name": "frontend",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@dbml/core": "^2.5.4",
"@douyinfe/semi-ui": "^2.36.0", "@douyinfe/semi-ui": "^2.36.0",
"@monaco-editor/react": "^4.5.1", "@monaco-editor/react": "^4.5.1",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
@ -24,10 +23,12 @@
"react-hotkeys-hook": "^4.4.1", "react-hotkeys-hook": "^4.4.1",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"socket.io-client": "^4.7.2",
"url": "^0.11.1", "url": "^0.11.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"tailwindcss": "^3.3.2" "tailwindcss": "^3.3.2"
} }
}, },
@ -724,9 +725,16 @@
} }
}, },
"node_modules/@babel/plugin-proposal-private-property-in-object": { "node_modules/@babel/plugin-proposal-private-property-in-object": {
"version": "7.21.0-placeholder-for-preset-env.2", "version": "7.21.11",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.11.tgz",
"integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "integrity": "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw==",
"dev": true,
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.18.6",
"@babel/helper-create-class-features-plugin": "^7.21.0",
"@babel/helper-plugin-utils": "^7.20.2",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
},
"engines": { "engines": {
"node": ">=6.9.0" "node": ">=6.9.0"
}, },
@ -1984,6 +1992,17 @@
"@babel/core": "^7.0.0-0" "@babel/core": "^7.0.0-0"
} }
}, },
"node_modules/@babel/preset-env/node_modules/@babel/plugin-proposal-private-property-in-object": {
"version": "7.21.0-placeholder-for-preset-env.2",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
"integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
"engines": {
"node": ">=6.9.0"
},
"peerDependencies": {
"@babel/core": "^7.0.0-0"
}
},
"node_modules/@babel/preset-env/node_modules/semver": { "node_modules/@babel/preset-env/node_modules/semver": {
"version": "6.3.0", "version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
@ -2393,16 +2412,6 @@
"postcss-selector-parser": "^6.0.10" "postcss-selector-parser": "^6.0.10"
} }
}, },
"node_modules/@dbml/core": {
"version": "2.5.4",
"resolved": "https://registry.npmjs.org/@dbml/core/-/core-2.5.4.tgz",
"integrity": "sha512-bfLb59z6pExD64eFUZTiRQfVW853v+vsfQd1bOKAZm4fHozGYVyQnM5WI4AahkAy+Jwm9NKr/b0wmrT/Hyft1w==",
"dependencies": {
"lodash": "^4.17.15",
"parsimmon": "^1.13.0",
"pluralize": "^8.0.0"
}
},
"node_modules/@douyinfe/semi-animation": { "node_modules/@douyinfe/semi-animation": {
"version": "2.37.0", "version": "2.37.0",
"resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.37.0.tgz", "resolved": "https://registry.npmjs.org/@douyinfe/semi-animation/-/semi-animation-2.37.0.tgz",
@ -3859,6 +3868,11 @@
"@sinonjs/commons": "^1.7.0" "@sinonjs/commons": "^1.7.0"
} }
}, },
"node_modules/@socket.io/component-emitter": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz",
"integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg=="
},
"node_modules/@surma/rollup-plugin-off-main-thread": { "node_modules/@surma/rollup-plugin-off-main-thread": {
"version": "2.2.3", "version": "2.2.3",
"resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz",
@ -7300,6 +7314,46 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/engine.io-client": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.2.tgz",
"integrity": "sha512-CQZqbrpEYnrpGqC07a9dJDz4gePZUgTPMU3NKJPSeQOyw27Tst4Pl3FemKoFGAlHzgZmKjoRmiJvbWfhCXUlIg==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1",
"engine.io-parser": "~5.2.1",
"ws": "~8.11.0",
"xmlhttprequest-ssl": "~2.0.0"
}
},
"node_modules/engine.io-client/node_modules/ws": {
"version": "8.11.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
"integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": "^5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
},
"node_modules/engine.io-parser": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.1.tgz",
"integrity": "sha512-9JktcM3u18nU9N2Lz3bWeBgxVgOKpw7yhRaoxQA3FUDZzzw+9WlA6p4G4u0RixNkg14fH7EfEc/RhpurtiROTQ==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/enhanced-resolve": { "node_modules/enhanced-resolve": {
"version": "5.15.0", "version": "5.15.0",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
@ -13221,11 +13275,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/parsimmon": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/parsimmon/-/parsimmon-1.18.1.tgz",
"integrity": "sha512-u7p959wLfGAhJpSDJVYXoyMCXWYwHia78HhRBWqk7AIbxdmlrfdp5wX0l3xv/iTSH5HvhN9K7o26hwwpgS5Nmw=="
},
"node_modules/pascal-case": { "node_modules/pascal-case": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz",
@ -13440,14 +13489,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/pluralize": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz",
"integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==",
"engines": {
"node": ">=4"
}
},
"node_modules/postcss": { "node_modules/postcss": {
"version": "8.4.24", "version": "8.4.24",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz",
@ -15901,6 +15942,32 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/socket.io-client": {
"version": "4.7.2",
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz",
"integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.2",
"engine.io-client": "~6.5.2",
"socket.io-parser": "~4.2.4"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
"dependencies": {
"@socket.io/component-emitter": "~3.1.0",
"debug": "~4.3.1"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/sockjs": { "node_modules/sockjs": {
"version": "0.3.24", "version": "0.3.24",
"resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz",
@ -17989,6 +18056,14 @@
"resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
"integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
}, },
"node_modules/xmlhttprequest-ssl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz",
"integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/y18n": { "node_modules/y18n": {
"version": "5.0.8", "version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",

View File

@ -18,6 +18,7 @@
"react-hotkeys-hook": "^4.4.1", "react-hotkeys-hook": "^4.4.1",
"react-router-dom": "^6.11.2", "react-router-dom": "^6.11.2",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"socket.io-client": "^4.7.2",
"url": "^0.11.1", "url": "^0.11.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
@ -46,6 +47,7 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"tailwindcss": "^3.3.2" "tailwindcss": "^3.3.2"
} }
} }

40
src/components/chat.jsx Normal file
View File

@ -0,0 +1,40 @@
import React, { useContext, useState } from "react";
import { Button, Input } from "@douyinfe/semi-ui";
import { IconSend } from "@douyinfe/semi-icons";
import { socket } from "../data/socket";
import { MessageContext } from "../pages/editor";
export default function Chat() {
const [message, setMessage] = useState("");
const { messages, setMessages } = useContext(MessageContext);
return (
<div className="mx-5 flex flex-col h-full">
<div className="h-full flex-1 overflow-y-auto" id="message-box">
{messages.map((m, i) => (
<div key={i}>{m}</div>
))}
</div>
<form
onSubmit={(e) => {
e.preventDefault();
if (message !== "") {
setMessages((prev) => [...prev, message]);
socket.emit("send-message", message);
}
setMessage("");
}}
className="flex"
>
<Input
onChange={(v) => setMessage(v)}
placeholder="Message"
value={message}
autoComplete="off"
className="me-2"
></Input>
<Button icon={<IconSend />} htmlType="submit"></Button>
</form>
</div>
);
}

View File

@ -5,35 +5,33 @@ import { SettingsContext } from "../pages/editor";
export default function Issues() { export default function Issues() {
const { settings } = useContext(SettingsContext); const { settings } = useContext(SettingsContext);
return ( return (
<div> <Collapse style={{ width: "100%" }}>
<Collapse style={{ width: "100%" }}> <Collapse.Panel
<Collapse.Panel header={
header={ <div>
<div> <i className="fa-solid fa-triangle-exclamation me-1 text-yellow-500"></i>{" "}
<i className="fa-solid fa-triangle-exclamation me-1 text-yellow-500"></i>{" "} Issues
Issues
</div>
}
itemKey="1"
>
<div className="max-h-[160px] overflow-y-auto">
{settings.strictMode ? (
<div className="mb-1">
Strict mode is off so no issues will be displayed.
</div>
) : (
<div>
<div className="py-2">Issue 1</div>
<div className="py-2">Issue 2</div>
<div className="py-2">Issue 3</div>
<div className="py-2">Issue 4</div>
<div className="py-2">Issue 5</div>
<div className="py-2">Issue 6</div>
</div>
)}
</div> </div>
</Collapse.Panel> }
</Collapse> itemKey="1"
</div> >
<div className="max-h-[160px] overflow-y-auto">
{settings.strictMode ? (
<div className="mb-1">
Strict mode is off so no issues will be displayed.
</div>
) : (
<div>
<div className="py-2">Issue 1</div>
<div className="py-2">Issue 2</div>
<div className="py-2">Issue 3</div>
<div className="py-2">Issue 4</div>
<div className="py-2">Issue 5</div>
<div className="py-2">Issue 6</div>
</div>
)}
</div>
</Collapse.Panel>
</Collapse>
); );
} }

View File

@ -7,6 +7,7 @@ import todo from "../assets/calendar.png";
import { Tooltip, SideSheet, List } from "@douyinfe/semi-ui"; import { Tooltip, SideSheet, List } from "@douyinfe/semi-ui";
import { UndoRedoContext } from "../pages/editor"; import { UndoRedoContext } from "../pages/editor";
import Todo from "./todo"; import Todo from "./todo";
import Chat from "./chat";
export default function Sidebar() { export default function Sidebar() {
const SidesheetType = { const SidesheetType = {
@ -54,6 +55,8 @@ export default function Sidebar() {
return renderTimeline(); return renderTimeline();
case SidesheetType.TODO: case SidesheetType.TODO:
return <Todo />; return <Todo />;
case SidesheetType.CHAT:
return <Chat />;
default: default:
break; break;
} }
@ -117,8 +120,10 @@ export default function Sidebar() {
return ( return (
<List> <List>
{[...undoStack].reverse().map((e) => ( {[...undoStack].reverse().map((e) => (
<List.Item style={{ padding: "4px 18px 4px 18px" }} <List.Item
className="hover:bg-slate-100"> style={{ padding: "4px 18px 4px 18px" }}
className="hover:bg-slate-100"
>
<div className="flex items-center py-1 w-full"> <div className="flex items-center py-1 w-full">
<i className="block fa-regular fa-circle fa-xs"></i> <i className="block fa-regular fa-circle fa-xs"></i>
<div className="ms-2">{e.message}</div> <div className="ms-2">{e.message}</div>

View File

@ -104,6 +104,7 @@ export default function Todo() {
<Dropdown.Menu> <Dropdown.Menu>
{Object.values(SortOrder).map((order) => ( {Object.values(SortOrder).map((order) => (
<Dropdown.Item <Dropdown.Item
key={order}
onClick={() => { onClick={() => {
setSortOrder(order); setSortOrder(order);
sort(order); sort(order);

7
src/data/socket.js Normal file
View File

@ -0,0 +1,7 @@
import { io } from "socket.io-client";
const URL = "http://localhost:5000";
export const socket = io(URL, {
autoConnect: false,
});

View File

@ -10,6 +10,7 @@ import {
Action, Action,
ObjectType, ObjectType,
} from "../data/data"; } from "../data/data";
import { socket } from "../data/socket";
export const LayoutContext = createContext(); export const LayoutContext = createContext();
export const TableContext = createContext(); export const TableContext = createContext();
@ -20,6 +21,7 @@ export const SettingsContext = createContext();
export const UndoRedoContext = createContext(); export const UndoRedoContext = createContext();
export const SelectContext = createContext(); export const SelectContext = createContext();
export const TaskContext = createContext(); export const TaskContext = createContext();
export const MessageContext = createContext();
export default function Editor(props) { export default function Editor(props) {
const [tables, setTables] = useState([]); const [tables, setTables] = useState([]);
@ -49,6 +51,7 @@ export default function Editor(props) {
showGrid: true, showGrid: true,
}); });
const [tasks, setTasks] = useState([]); const [tasks, setTasks] = useState([]);
const [messages, setMessages] = useState([]);
const [undoStack, setUndoStack] = useState([]); const [undoStack, setUndoStack] = useState([]);
const [redoStack, setRedoStack] = useState([]); const [redoStack, setRedoStack] = useState([]);
const [selectedElement, setSelectedElement] = useState({ const [selectedElement, setSelectedElement] = useState({
@ -395,6 +398,19 @@ export default function Editor(props) {
useEffect(() => { useEffect(() => {
document.title = "Editor - drawDB"; document.title = "Editor - drawDB";
socket.connect();
const onConnect = () => console.log(`You connected with id: ${socket.id}`);
const onRecieve = (value) => setMessages((prev) => [...prev, value]);
socket.on("connect", onConnect);
socket.on("recieve-message", onRecieve);
return () => {
socket.off("connect", onConnect);
socket.off("recieve-message", onRecieve);
};
}, []); }, []);
return ( return (
@ -449,7 +465,13 @@ export default function Editor(props) {
/> />
)} )}
<Canvas /> <Canvas />
{layout.services && <Sidebar />} {layout.services && (
<MessageContext.Provider
value={{ messages, setMessages }}
>
<Sidebar />
</MessageContext.Provider>
)}
</div> </div>
</div> </div>
</TaskContext.Provider> </TaskContext.Provider>