Site: update site structure and add architecture page (#2675)

* remove blog

* fix: license

* chore: bump docusaurus

* separate benchmark page

* move to sub folder

* fix blog path

* Chore: update site

* fix: only deploy on push and dispatch

* fix: on:

* ci: merge workflow

* ci: fix if

* refactor: dump preset
This commit is contained in:
Jonathan Ho
2022-12-04 08:36:10 -06:00
committed by GitHub
parent ef452b5d54
commit 987b4058cb
56 changed files with 7578 additions and 5162 deletions
-8
View File
@@ -1,8 +0,0 @@
---
slug: welcome
title: Welcome
authors: [itoh, skillz]
tags: [discordeno, hello]
---
Hello and Welcome to Discordeno, a highly scalable Discord library for Deno and Node.js using TypeScript.
-11
View File
@@ -1,11 +0,0 @@
itoh:
name: ITOH
title: Maintainer of Discordeno
url: https://github.com/itohatweb
image_url: https://github.com/itohatweb.png
skillz:
name: Skillz
title: Maintainer of Discordeno
url: https://github.com/Skillz4Killz
image_url: https://github.com/Skillz4Killz.png
+49
View File
@@ -0,0 +1,49 @@
---
sidebar_position: 2
---
import BrowserOnly from '@docusaurus/BrowserOnly';
# Architecture
## Overview
import FlowChart from '@site/src/components/architecture/FlowChart'
<BrowserOnly>
{() => <FlowChart />}
</BrowserOnly>
Discordeno have three main components/process, gateway, bot and rest. The Gateway process is responsible for handling and maintaining the websocket with discord, the websocket events from discord, such as connection, resuming, heartbeating and sending websocket message to discord. The Bot process is responsible for handling and converting all events from discord and trigger your code, like run function on message create. The Rest process is responsible for handling/fetching all http requests to discord, such as ratelimiting and proxying.
## Gateway Process
import FlowChart2 from '@site/src/components/architecture/FlowChart2'
<BrowserOnly>
{() => <FlowChart2 />}
</BrowserOnly>
The Gateway process have two part the gateway manager and the gateway [shard](https://discord.com/developers/docs/topics/gateway#sharding), the gateway manager oversee the gateway shard.
### Gateway Manager
The gateway manager spawn the right amount of shard acording to data from discord's [getGatewayBot](https://discord.com/developers/docs/topics/gateway#get-gateway-bot) endpoint, user can override the value of gatewayBot by directly passing the value. The manager control the order or sequence of shard identifying base on the session start limit listed in the getGatewayBot to prevent hitting the ratelimiting. By default the manager will check the getGatewayBot endpoint every 8 hours and reshard if the number of shard changed shard. Check [here](/tutorial/big-bot-guide/gateway#understanding-gateway-manager) for more information about the gateway manager.
### Gateway Shard
The gateway shard create a websocket connect to discord, and pass any event to the handleMessage function. The handleMessage function will check the event and intercept/process websocket related event like hello, resume, heartbeat, ready, only pass real event to the bot. You may customize the handleMessage to you own case, but it is not recommand unless you know what youd doing, as it is vital for the connection. After the function processed the event, the function will pass the event to the Bot proceess either directly (in same process), with rest api, with message queue, or with other method depend on the user customiztion.
## Bot Process
import FlowChart3 from '@site/src/components/architecture/FlowChart3'
<BrowserOnly>
{() => <FlowChart3 handlerFilter={(handler) => handler.startsWith('handleChannel')}/>}
</BrowserOnly>
A simplified version of function used inside of the bot process, showing only the handlers, transformers and event related to channel event
### Bot
The Bot process receive event from gateway and pass all the event to the handleDiscordPayload function. The handleDiscordPayload function will call raw event for all event, and route to three layer for process the event, the handler, transformers and event. The handler will transformer the data of event with transformers and call the event with the transformed data. The transformer will remove useless property, change the name, abstractify bitwise permission flags change transform the data to a javascript.
## Rest Process
TBC
+6 -3
View File
@@ -1,9 +1,12 @@
---
sidebar_position: 5
sidebar_position: 10
---
# Benchmark
import BenchmarkResultCharts from '@site/src/components/BenchmarkResultCharts'
Benchmark runs on every commit pushed on the Discordeno's main branch
import Benchmark from '@site/src/components/Benchmark'
<Benchmark />
<BenchmarkResultCharts/>
@@ -1,5 +1,5 @@
---
sidebar_position: 1
sidebar_position: 5
---
# Frequently Asked Questions
-4
View File
@@ -1,4 +0,0 @@
{
"label": "General",
"position": 1
}
@@ -1,5 +1,5 @@
---
sidebar_position: 2
sidebar_position: 3
---
# Getting Started
@@ -1,5 +1,5 @@
---
sidebar_position: 3
sidebar_position: 4
---
# Migrating
+1 -1
View File
@@ -14,7 +14,7 @@
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
// By default, Docusaurus generates a sidebar from the docs folder structure
tutorialSidebar: [{ type: "autogenerated", dirName: "." }],
docs: [{ type: "autogenerated", dirName: "." }],
// But you can create a sidebar manually
/*
tutorialSidebar: [
+91 -22
View File
@@ -23,14 +23,7 @@ const config = {
"classic",
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
sidebarPath: require.resolve("./sidebars.js"),
editUrl: "https://github.com/discordeno/discordeno/tree/main/site/",
},
blog: {
showReadingTime: true,
editUrl: "https://github.com/discordeno/discordeno/tree/main/site/",
},
docs: false,
theme: {
customCss: require.resolve("./src/css/custom.css"),
},
@@ -49,12 +42,19 @@ const config = {
},
items: [
{
type: "doc",
docId: "intro",
type: "docSidebar",
sidebarId: "docs",
position: "left",
label: "Docs",
docsPluginId: "docs",
},
{
type: "docSidebar",
sidebarId: "tutorial",
position: "left",
label: "Tutorial",
docsPluginId: "tutorial",
},
{ to: "/blog", label: "Blog", position: "left" },
{
href: "https://github.com/discordeno/discordeno",
label: "GitHub",
@@ -69,9 +69,38 @@ const config = {
title: "Docs",
items: [
{
label: "Docs",
label: "Introduction",
to: "/docs/intro",
},
{
label: "Getting Started",
to: "/docs/getting-started",
},
{
label: "FAQ",
to: "/docs/frequently-asked-questions",
},
{
label: "Benchmark",
to: "/docs/benchmark",
},
],
},
{
title: "Tutorial",
items: [
{
label: "Big Bot",
to: "/tutorial/big-bot-guide/step-by-step",
},
{
label: "Node.js",
to: "/tutorial/nodejs/getting-started",
},
{
label: "Amethyst",
to: "/tutorial/amethyst/intro",
},
],
},
{
@@ -86,10 +115,6 @@ const config = {
{
title: "More",
items: [
{
label: "Blog",
to: "/blog",
},
{
label: "GitHub",
href: "https://github.com/discordeno/discordeno",
@@ -106,25 +131,69 @@ const config = {
}),
plugins: [
// ... Your other plugins.
[
"@docusaurus/plugin-content-docs",
/** @type {import('@docusaurus/plugin-content-docs').Options} */
{
id: "docs",
path: "docs",
routeBasePath: "docs",
sidebarPath: require.resolve("./docsSidebars.js"),
editUrl: "https://github.com/discordeno/discordeno/tree/main/site/",
},
],
[
"@docusaurus/plugin-content-docs",
/** @type {import('@docusaurus/plugin-content-docs').Options} */
{
id: "tutorial",
path: "tutorial",
routeBasePath: "tutorial",
sidebarPath: require.resolve("./tutorialSidebars.js"),
editUrl: "https://github.com/discordeno/discordeno/tree/main/site/",
},
],
[
require.resolve("@easyops-cn/docusaurus-search-local"),
{
indexDocs: true,
indexBlog: true,
indexPages: true,
docsRouteBasePath: ["/docs"],
blogRouteBasePath: ["/blog"],
docsRouteBasePath: ["/docs", "/tutorial"],
language: ["en"],
hashed: true,
docsDir: ["docs"],
blogDir: ["blog"],
docsDir: ["docs", "tutorial"],
blogDir: [],
removeDefaultStopWordFilter: true,
highlightSearchTermsOnTargetPage: true,
searchResultLimits: 8,
searchResultContextMaxLength: 50,
},
],
[
"client-redirects",
/** @type {import('@docusaurus/plugin-client-redirects').Options} */
{
createRedirects(existingPath) {
if (
existingPath.includes("/tutorial/big-bot-guide/") || existingPath.includes("/tutorial/nodejs/") ||
existingPath.includes("/tutorial/amethyst/")
) {
return [
existingPath.replace("/tutorial/", "/docs/"),
];
}
if (
existingPath.includes("/docs/docs/frequently-asked-questions") ||
existingPath.includes("/docs/docs/getting-started") || existingPath.includes("/docs/docs/migrating")
) {
return [
existingPath.replace("/docs/", "/docs/general/"),
];
}
return undefined; // Return a falsy value: no redirect created
},
},
],
],
};
+6099 -4924
View File
File diff suppressed because it is too large Load Diff
+11 -8
View File
@@ -2,10 +2,10 @@
"name": "site",
"version": "0.0.0",
"private": false,
"license": "Apache 2.0",
"license": "Apache-2.0",
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"start": "docusaurus start --host 0.0.0.0",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
@@ -16,20 +16,23 @@
"typecheck": "tsc"
},
"dependencies": {
"@docusaurus/core": "2.0.0-beta.15",
"@docusaurus/preset-classic": "2.0.0-beta.15",
"@docusaurus/core": "2.2.0",
"@docusaurus/plugin-client-redirects": "^2.2.0",
"@docusaurus/preset-classic": "2.2.0",
"@easyops-cn/docusaurus-search-local": "^0.21.4",
"@mdx-js/react": "^1.6.21",
"chart.js": "^2.9.4",
"chart.js": "^3.9.1",
"clsx": "^1.1.1",
"prism-react-renderer": "^1.2.1",
"react": "^17.0.1",
"react-chartjs-2": "^2.11.2",
"react-dom": "^17.0.1"
"react-chartjs-2": "^4.3.1",
"react-dom": "^17.0.1",
"reactflow": "^11.2.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.0.0-beta.15",
"@docusaurus/module-type-aliases": "2.2.0",
"@tsconfig/docusaurus": "^1.0.4",
"@types/chart.js": "^2.9.37",
"typescript": "^4.5.2"
},
"browserslist": {
+173
View File
@@ -0,0 +1,173 @@
import {
CategoryScale,
Chart as ChartJS,
Legend,
LinearScale,
LineController,
LineElement,
PointElement,
Title,
Tooltip,
} from "chart.js";
import React, { useEffect, useState } from "react";
import { Chart } from "react-chartjs-2";
ChartJS.register(CategoryScale, LineController, LinearScale, PointElement, LineElement, Title, Tooltip, Legend);
const BenchmarkResultChart = ({ name, dataset }: {
name: string;
dataset: {
bench: {
name: string;
range: string | number;
unit: string;
value: string | number;
extra: string | number | undefined;
};
commit: {
author: {
email: string;
name: string;
username: string;
};
committer: {
email: string;
name: string;
username: string;
};
distinct: true;
id: string;
message: string;
timestamp: string;
tree_id: string;
url: string;
};
date: number;
tool: string;
}[];
}) => {
const data = {
labels: dataset.map((d) => d.commit.id.slice(0, 7)),
datasets: [
{
label: name,
data: dataset.map((d) => d.bench.value),
borderColor: "#ff3838",
backgroundColor: "#ff383860", // Add alpha for #rrggbbaa
},
],
};
return (
<Chart
type="line"
data={data}
options={{
responsive: true,
scales: {
x: {
title: {
display: true,
text: "commit",
},
},
y: {
title: {
display: true,
text: dataset.length > 0 ? dataset[0].bench.unit : "",
},
beginAtZero: true,
},
},
plugins: {
tooltip: {
callbacks: {
afterTitle: (items) => {
const index = items[0].dataIndex;
const data = dataset[index];
return "\n" + data.commit.message + "\n\n" + data.commit.timestamp + " committed by @" +
data.commit.author.username + "\n";
},
label: (item) => {
let label = item.formattedValue;
const { range, unit } = dataset[item.datasetIndex].bench;
label += " " + unit;
if (range) {
label += " (" + range + ")";
}
return label;
},
afterLabel: (item) => {
const { extra } = dataset[item.datasetIndex].bench;
return extra ? "\n" + extra : "";
},
},
},
},
onClick: (_mouseEvent, activeElems) => {
if (activeElems.length === 0) {
return;
}
// XXX: Undocumented. How can we know the index?
const index = activeElems[0].index;
const url = dataset[index].commit.url;
window.open(url, "_blank");
},
}}
/>
);
};
export default function BenchmarkResultCharts(): JSX.Element {
const [data, setData] = useState<{ entries: { Benchmark: [] } }>();
useEffect(() => {
if (!data) {
(async () => {
setData(
JSON.parse(
(await (await fetch(
"https://raw.githubusercontent.com/discordeno/discordeno/benchies/benchmarksResult/data.js",
)).text()).slice(24),
),
);
})();
}
}, []);
function collectBenchesPerTestCase(entries) {
const dataMap = new Map();
for (const entry of entries) {
const { commit, date, tool, benches } = entry;
for (const bench of benches) {
const result = { commit, date, tool, bench };
const arr = dataMap.get(bench.name);
if (arr === undefined) {
dataMap.set(bench.name, [result]);
} else {
arr.push(result);
}
}
}
return dataMap;
}
return (
<div style={{ minHeight: "100vh" }}>
{data
? Array.from(
collectBenchesPerTestCase(data.entries.Benchmark),
([key, value]) => ({ benchName: key, benches: value }),
).map((
bench,
index,
) => (
<BenchmarkResultChart
key={index}
name={bench.benchName}
dataset={bench.benches}
/>
))
: <></>}
</div>
);
}
@@ -1,147 +0,0 @@
import { useColorMode } from "@docusaurus/theme-common";
import React, { useEffect, useState } from "react";
import { Line } from "react-chartjs-2";
// Colors from https://github.com/github/linguist/blob/master/lib/linguist/languages.yml
const toolColors = {
cargo: "#dea584",
go: "#00add8",
benchmarkjs: "#f1e05a",
benchmarkluau: "#000080",
pytest: "#3572a5",
googlecpp: "#f34b7d",
catch2: "#f34b7d",
julia: "#a270ba",
benchmarkdotnet: "#178600",
customBiggerIsBetter: "#38ff38",
customSmallerIsBetter: "#ff3838",
_: "#333333",
};
const BenchmarkResultChart = ({ name, dataset, theme }) => {
const color = toolColors[dataset.length > 0 ? dataset[0].tool : "_"];
const data = {
labels: dataset.map((d) => d.commit.id.slice(0, 7)),
datasets: [
{
label: name,
data: dataset.map((d) => d.bench.value),
borderColor: color,
backgroundColor: color + "60", // Add alpha for #rrggbbaa
},
],
};
const options = {
scales: {
xAxes: [
{
scaleLabel: {
display: true,
labelString: "commit",
},
},
],
yAxes: [
{
scaleLabel: {
display: true,
labelString: dataset.length > 0 ? dataset[0].bench.unit : "",
},
ticks: {
beginAtZero: true,
},
},
],
legend: {
labels: {
// This more specific font property overrides the global property
defaultFontColor: theme === "light" ? "#000000" : "#FFFFFF",
},
},
},
tooltips: {
callbacks: {
afterTitle: (items) => {
const { index } = items[0];
const data = dataset[index];
return "\n" + data.commit.message + "\n\n" + data.commit.timestamp + " committed by @" +
data.commit.committer.username + "\n";
},
label: (item) => {
let label = item.value;
const { range, unit } = dataset[item.index].bench;
label += " " + unit;
if (range) {
label += " (" + range + ")";
}
return label;
},
afterLabel: (item) => {
const { extra } = dataset[item.index].bench;
return extra ? "\n" + extra : "";
},
},
},
onClick: (_mouseEvent, activeElems) => {
if (activeElems.length === 0) {
return;
}
// XXX: Undocumented. How can we know the index?
const index = activeElems[0]._index;
const url = dataset[index].commit.url;
window.open(url, "_blank");
},
};
// console.log(theme);
return <Line data={data} options={options} />;
};
export default function BenchmarkResultCharts() {
const { colorMode } = useColorMode();
const [data, setData] = useState();
useEffect(async () => {
if (!data) {
setData(
JSON.parse(
(await (await fetch(
"https://raw.githubusercontent.com/discordeno/discordeno/benchies/benchmarksResult/data.js",
)).text()).slice(24),
),
);
}
}, []);
function collectBenchesPerTestCase(entries) {
const dataMap = new Map();
for (const entry of entries) {
const { commit, date, tool, benches } = entry;
for (const bench of benches) {
const result = { commit, date, tool, bench };
const arr = dataMap.get(bench.name);
if (arr === undefined) {
dataMap.set(bench.name, [result]);
} else {
arr.push(result);
}
}
}
return dataMap;
}
return (data
? Array.from(
collectBenchesPerTestCase(data.entries.Benchmark),
([key, value]) => ({ benchName: key, benches: value }),
).map((
bench,
index,
) => (
<BenchmarkResultChart
key={index}
name={bench.benchName}
dataset={bench.benches}
theme={""}
/>
))
: <></>);
}
@@ -0,0 +1,93 @@
import React, { useEffect, useState } from "react";
import ReactFlow, { Background, Controls, Edge, Handle, Node, Position, useEdgesState, useNodesState } from "reactflow";
import "reactflow/dist/style.css";
export const multiplier = 225;
export const height = 40;
export const widthMultiplier = 0.75;
export const defaultNodeOptions = {
targetPosition: Position.Left,
sourcePosition: Position.Right,
draggable: false,
style: { width: `${multiplier * 0.75}px`, height: `${height}px` },
};
export const defaultGroupOptions = {
draggable: false,
};
export default function BaseFlowChart(
{ initialNodes = [], initialEdges = [] }: { initialNodes: Node[]; initialEdges: Edge[] },
) {
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
return (
<>
<div
style={{
width: windowDimensions.width >= 997
? `${
(100 *
((windowDimensions.width - 300 -
(windowDimensions.width >= 1620 ? (windowDimensions.width - 1620) * 0.5 : 0)) /
windowDimensions.width) - 2) * widthMultiplier
}vw`
: "95vw",
height: "25vh",
}}
>
<ReactFlow
nodes={nodes}
edges={edges}
defaultEdgeOptions={{ focusable: false, animated: true }}
nodeTypes={{
baseLineNode: () => (
<div style={{ height: "1px", width: "20px" }}>
<Handle
type="target"
position={Position.Bottom}
style={{ background: "rgba(0,0,0,0)", borderColor: "rgba(0,0,0,0)" }}
/>
<Handle
type="source"
position={Position.Top}
style={{ background: "rgba(0,0,0,0)", borderColor: "rgba(0,0,0,0)" }}
/>
</div>
),
baseLineNodeText: (n) => (
<div style={{ textAlign: "center", width: defaultNodeOptions.style.width }}>
<h3>{n.data.label}</h3>
</div>
),
}}
fitView
>
<Controls />
<Background />
</ReactFlow>
</div>
</>
);
}
@@ -0,0 +1,103 @@
import React from "react";
import { Edge, Node } from "reactflow";
import "reactflow/dist/style.css";
import BaseFlowChart, { defaultNodeOptions, multiplier } from "./BaseFlowChart";
const initialNodes: Node[] = [
{
id: "discordGateway",
type: "input",
position: { x: 0 * multiplier, y: 0 },
data: { label: "Discord Gateway" },
...defaultNodeOptions,
},
{ id: "gateway", position: { x: 1 * multiplier, y: 0 }, data: { label: "Gateway" }, ...defaultNodeOptions },
{ id: "baseLineNode-1", type: "baseLineNode", position: { x: 0.85 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-2", type: "baseLineNode", position: { x: 0.85 * multiplier, y: -130 }, data: {} },
{ id: "baseLineNode-3", type: "baseLineNode", position: { x: 2.85 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-4", type: "baseLineNode", position: { x: 2.85 * multiplier, y: -130 }, data: {} },
{ id: "baseLineNode-5", type: "baseLineNode", position: { x: 3.85 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-6", type: "baseLineNode", position: { x: 3.85 * multiplier, y: -130 }, data: {} },
{ id: "baseLineNode-7", type: "baseLineNode", position: { x: 4.85 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-8", type: "baseLineNode", position: { x: 4.85 * multiplier, y: -130 }, data: {} },
{
id: "baseLineNodeText-1",
type: "baseLineNodeText",
position: { x: 0 * multiplier, y: -130 },
data: { label: "Discord" },
},
{
id: "baseLineNodeText-2",
type: "baseLineNodeText",
position: { x: 1.5 * multiplier, y: -130 },
data: { label: "Event In" },
},
{
id: "baseLineNodeText-3",
type: "baseLineNodeText",
position: { x: 3 * multiplier, y: -130 },
data: { label: "Event Processing" },
},
{
id: "baseLineNodeText-4",
type: "baseLineNodeText",
position: { x: 4 * multiplier, y: -130 },
data: { label: "Event out" },
},
{
id: "baseLineNodeText-6",
type: "baseLineNodeText",
position: { x: 5 * multiplier, y: -130 },
data: { label: "Discord" },
},
{ id: "bot", position: { x: 2 * multiplier, y: 0 }, data: { label: "Bot" }, ...defaultNodeOptions },
{ id: "yourCode", position: { x: 3 * multiplier, y: 0 }, data: { label: "Your Code" }, ...defaultNodeOptions },
{ id: "rest", position: { x: 4 * multiplier, y: 0 }, data: { label: "Rest" }, ...defaultNodeOptions },
{
id: "discordApiGateway",
type: "output",
position: { x: 5 * multiplier, y: 0 },
data: { label: "Discord Api" },
...defaultNodeOptions,
},
];
const initialEdges: Edge[] = [
{ id: "d-g", source: "discordGateway", target: "gateway" },
{ id: "g-b", source: "gateway", target: "bot" },
{ id: "b-y", source: "bot", target: "yourCode" },
{ id: "y-r", source: "yourCode", target: "rest" },
{ id: "r-d", source: "rest", target: "discordApiGateway" },
{
id: "baseLine-1",
source: "baseLineNode-1",
target: "baseLineNode-2",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
{
id: "baseLine-2",
source: "baseLineNode-3",
target: "baseLineNode-4",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
{
id: "baseLine-3",
source: "baseLineNode-5",
target: "baseLineNode-6",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
{
id: "baseLine-4",
source: "baseLineNode-7",
target: "baseLineNode-8",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
];
export default function FlowChart() {
return <BaseFlowChart initialNodes={initialNodes} initialEdges={initialEdges} />;
}
@@ -0,0 +1,198 @@
import React from "react";
import { Edge, Node, Position } from "reactflow";
import "reactflow/dist/style.css";
import BaseFlowChart, { defaultGroupOptions, defaultNodeOptions, multiplier } from "./BaseFlowChart";
const initialNodes: Node[] = [
{
id: "discordGateway",
type: "input",
position: { x: 0 * multiplier, y: 0 },
data: { label: "Discord Gateway" },
...defaultNodeOptions,
},
{ id: "baseLineNode-1", type: "baseLineNode", position: { x: 0.85 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-2", type: "baseLineNode", position: { x: 0.85 * multiplier, y: -130 }, data: {} },
{ id: "baseLineNode-3", type: "baseLineNode", position: { x: 3.75 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-4", type: "baseLineNode", position: { x: 3.75 * multiplier, y: -130 }, data: {} },
{
id: "baseLineNodeText-1",
type: "baseLineNodeText",
position: { x: 0 * multiplier, y: -130 },
data: { label: "Discord" },
},
{
id: "baseLineNodeText-2",
type: "baseLineNodeText",
position: { x: 2 * multiplier, y: -130 },
data: { label: "Gateway" },
},
{
id: "baseLineNodeText-3",
type: "baseLineNodeText",
position: { x: 4 * multiplier, y: -130 },
data: { label: "Bot" },
},
{
id: "gatewayManager",
type: "input",
position: { x: 2.0625 * multiplier, y: -80 },
data: { label: "Gateway Manager" },
...defaultNodeOptions,
targetPosition: Position.Top,
sourcePosition: Position.Bottom,
},
{
id: "shard-1",
type: "output",
position: { x: 1.25 * multiplier, y: -20 },
data: { label: "Shard-1" },
style: { width: `${multiplier * 2}px`, height: "80px" },
...defaultGroupOptions,
},
{
id: "shard-1-socket",
position: { x: 0.125 * multiplier, y: 20 },
data: { label: "webSocket" },
...defaultNodeOptions,
parentNode: "shard-1",
extent: "parent",
},
{
id: "shard-1-handleMessage",
position: { x: 1.125 * multiplier, y: 20 },
data: { label: "HandleMessage" },
...defaultNodeOptions,
parentNode: "shard-1",
extent: "parent",
},
{
id: "shard-2",
type: "output",
position: { x: 1.375 * multiplier, y: 0 },
data: { label: "Shard-2" },
style: { width: `${multiplier * 2}px`, height: "80px" },
...defaultGroupOptions,
},
{
id: "shard-2-socket",
position: { x: 0.125 * multiplier, y: 20 },
data: { label: "webSocket" },
...defaultNodeOptions,
parentNode: "shard-2",
extent: "parent",
},
{
id: "shard-2-handleMessage",
position: { x: 1.125 * multiplier, y: 20 },
data: { label: "HandleMessage" },
...defaultNodeOptions,
parentNode: "shard-2",
extent: "parent",
},
{
id: "shard-3",
type: "output",
position: { x: 1.5 * multiplier, y: 20 },
data: { label: "Shard-3" },
style: { width: `${multiplier * 2}px`, height: "80px" },
...defaultGroupOptions,
},
{
id: "shard-3-socket",
position: { x: 0.125 * multiplier, y: 20 },
data: { label: "webSocket" },
...defaultNodeOptions,
parentNode: "shard-3",
extent: "parent",
},
{
id: "shard-3-handleMessage",
position: { x: 1.125 * multiplier, y: 20 },
data: { label: "HandleMessage" },
...defaultNodeOptions,
parentNode: "shard-3",
extent: "parent",
},
{
id: "shard-n",
type: "output",
position: { x: 1.625 * multiplier, y: 40 },
data: { label: "Shard-N" },
style: { width: `${multiplier * 2}px`, height: "80px" },
...defaultGroupOptions,
},
{
id: "shard-n-socket",
position: { x: 0.125 * multiplier, y: 20 },
data: { label: "webSocket" },
...defaultNodeOptions,
parentNode: "shard-n",
extent: "parent",
},
{
id: "shard-n-handleMessage",
position: { x: 1.125 * multiplier, y: 20 },
data: { label: "HandleMessage" },
...defaultNodeOptions,
parentNode: "shard-n",
extent: "parent",
},
{ id: "bot", type: "output", position: { x: 4 * multiplier, y: 0 }, data: { label: "Bot" }, ...defaultNodeOptions },
];
const initialEdges: Edge[] = [
{ id: "d-g", source: "discordGateway", target: "gateway" },
{ id: "g-b", source: "gateway", target: "bot" },
{ id: "b-y", source: "bot", target: "yourCode" },
{ id: "y-r", source: "yourCode", target: "rest" },
{ id: "r-d", source: "rest", target: "discordApiGateway" },
{
id: "baseLine-1",
source: "baseLineNode-1",
target: "baseLineNode-2",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
{
id: "baseLine-2",
source: "baseLineNode-3",
target: "baseLineNode-4",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
{
id: "baseLine-3",
source: "baseLineNode-5",
target: "baseLineNode-6",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
{
id: "baseLine-4",
source: "baseLineNode-7",
target: "baseLineNode-8",
style: { stroke: "blue", strokeDasharray: 20 },
animated: false,
},
{ id: "d-shard-1", source: "discordGateway", target: "shard-1-socket", zIndex: 100 },
{ id: "d-shard-2", source: "discordGateway", target: "shard-2-socket", zIndex: 100 },
{ id: "d-shard-3", source: "discordGateway", target: "shard-3-socket", zIndex: 100 },
{ id: "d-shard-n", source: "discordGateway", target: "shard-n-socket", zIndex: 100 },
{ id: "shard-1-socket-handleMessage", source: "shard-1-socket", target: "shard-1-handleMessage", zIndex: 100 },
{ id: "shard-2-socket-handleMessage", source: "shard-2-socket", target: "shard-2-handleMessage", zIndex: 100 },
{ id: "shard-3-socket-handleMessage", source: "shard-3-socket", target: "shard-3-handleMessage", zIndex: 100 },
{ id: "shard-n-socket-handleMessage", source: "shard-n-socket", target: "shard-n-handleMessage", zIndex: 100 },
{ id: "shard-1-handleMessage-bot", source: "shard-1-handleMessage", target: "bot", zIndex: 100 },
{ id: "shard-2-handleMessage-bot", source: "shard-2-handleMessage", target: "bot", zIndex: 100 },
{ id: "shard-3-handleMessage-bot", source: "shard-3-handleMessage", target: "bot", zIndex: 100 },
{ id: "shard-n-handleMessage-bot", source: "shard-n-handleMessage", target: "bot", zIndex: 100 },
{ id: "gatewayManager-shard-1", source: "gatewayManager", target: "shard-1", zIndex: 10 },
{ id: "gatewayManager-shard-2", source: "gatewayManager", target: "shard-2", zIndex: 100 },
{ id: "gatewayManager-shard-3", source: "gatewayManager", target: "shard-3", zIndex: 100 },
{ id: "gatewayManager-shard-n", source: "gatewayManager", target: "shard-n", zIndex: 100 },
];
export default function FlowChart2() {
return <BaseFlowChart initialNodes={initialNodes} initialEdges={initialEdges} />;
}
@@ -0,0 +1,669 @@
import React, { useEffect, useState } from "react";
import ReactFlow, {
Background,
Controls,
Edge,
Handle,
Node,
NodeMouseHandler,
Position,
useEdgesState,
useNodesState,
} from "reactflow";
import "reactflow/dist/style.css";
import { defaultNodeOptions, height, multiplier, widthMultiplier } from "./BaseFlowChart";
const handlers: {
[index: string]: {
transformers: string[];
event: string;
};
} = {
handleChannelCreate: { transformers: ["transformers.channel"], event: "events.channelCreate" },
handleChannelDelete: {
transformers: ["transformers.channel", "transformers.snowflake"],
event: "events.channelDelete",
},
handleChannelPinsUpdate: {
transformers: ["transformers.snowflake", "transformers.snowflake"],
event: "events.channelPinsUpdate",
},
handleChannelUpdate: { transformers: ["transformers.channel"], event: "events.channelUpdate" },
handleStageInstanceCreate: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.stageInstanceCreate",
},
handleStageInstanceDelete: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.stageInstanceDelete",
},
handleStageInstanceUpdate: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.stageInstanceUpdate",
},
handleThreadCreate: { transformers: ["transformers.channel"], event: "events.threadCreate" },
handleThreadDelete: { transformers: ["transformers.channel"], event: "events.threadDelete" },
handleThreadListSync: {
transformers: [
"transformers.snowflake",
"transformers.snowflake",
"transformers.channel",
"transformers.snowflake",
"transformers.snowflake",
],
event: undefined,
},
handleThreadMembersUpdate: {
transformers: [
"transformers.snowflake",
"transformers.snowflake",
"transformers.threadMember",
"transformers.snowflake",
],
event: "events.threadMembersUpdate",
},
handleThreadMemberUpdate: {
transformers: ["transformers.snowflake", "transformers.snowflake"],
event: "events.threadMemberUpdate",
},
handleThreadUpdate: { transformers: ["transformers.channel"], event: "events.threadUpdate" },
handleGuildEmojisUpdate: {
transformers: ["transformers.snowflake", "transformers.snowflake"],
event: "events.guildEmojisUpdate",
},
handleAutoModerationActionExecution: {
transformers: ["transformers.automodActionExecution"],
event: "events.automodActionExecution",
},
handleAutoModerationRuleCreate: { transformers: ["transformers.automodRule"], event: "events.automodRuleCreate" },
handleAutoModerationRuleDelete: { transformers: ["transformers.automodRule"], event: "events.automodRuleDelete" },
handleAutoModerationRuleUpdate: { transformers: ["transformers.automodRule"], event: "events.automodRuleUpdate" },
handleGuildBanAdd: {
transformers: ["transformers.user", "transformers.snowflake"],
event: "events.guildBanAdd",
},
handleGuildBanRemove: {
transformers: ["transformers.user", "transformers.snowflake"],
event: "events.guildBanRemove",
},
handleGuildCreate: { transformers: ["transformers.guild"], event: "events.guildCreate" },
handleGuildDelete: { transformers: ["transformers.snowflake"], event: "events.guildDelete" },
handleGuildIntegrationsUpdate: { transformers: ["transformers.snowflake"], event: "events.integrationUpdate" },
handleGuildUpdate: { transformers: ["transformers.guild"], event: "events.guildUpdate" },
handleGuildScheduledEventCreate: {
transformers: ["transformers.scheduledEvent"],
event: "events.scheduledEventCreate",
},
handleGuildScheduledEventDelete: {
transformers: ["transformers.scheduledEvent"],
event: "events.scheduledEventDelete",
},
handleGuildScheduledEventUpdate: {
transformers: ["transformers.scheduledEvent"],
event: "events.scheduledEventUpdate",
},
handleGuildScheduledEventUserAdd: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.scheduledEventUserAdd",
},
handleGuildScheduledEventUserRemove: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.scheduledEventUserRemove",
},
handleIntegrationCreate: { transformers: ["transformers.integration"], event: "events.integrationCreate" },
handleIntegrationDelete: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.integrationDelete",
},
handleIntegrationUpdate: { transformers: ["transformers.integration"], event: "events.integrationUpdate" },
handleInteractionCreate: {
transformers: ["transformers.snowflake", "transformers.interaction"],
event: "events.interactionCreate",
},
handleInviteCreate: { transformers: ["transformers.invite"], event: "events.inviteCreate" },
handleInviteDelete: {
transformers: ["transformers.snowflake", "transformers.snowflake"],
event: "events.inviteDelete",
},
handleGuildMembersChunk: {
transformers: [
"transformers.snowflake",
"transformers.member",
"transformers.snowflake",
"transformers.snowflake",
"transformers.user",
"transformers.activity",
],
event: undefined,
},
handleGuildMemberAdd: {
transformers: ["transformers.snowflake", "transformers.user", "transformers.member"],
event: "events.guildMemberAdd",
},
handleGuildMemberRemove: {
transformers: ["transformers.snowflake", "transformers.user"],
event: "events.guildMemberRemove",
},
handleGuildMemberUpdate: {
transformers: ["transformers.user", "transformers.member", "transformers.snowflake"],
event: "events.guildMemberUpdate",
},
handleMessageCreate: { transformers: ["transformers.message"], event: "events.messageCreate" },
handleMessageDelete: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.messageDelete",
},
handleMessageDeleteBulk: {
transformers: [
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
],
event: "events.messageDeleteBulk",
},
handleMessageReactionAdd: {
transformers: [
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.member",
"transformers.user",
"transformers.emoji",
],
event: "events.reactionAdd",
},
handleMessageReactionRemove: {
transformers: [
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.emoji",
],
event: "events.reactionRemove",
},
handleMessageReactionRemoveAll: {
transformers: ["transformers.snowflake", "transformers.snowflake", "transformers.snowflake"],
event: "events.reactionRemoveAll",
},
handleMessageReactionRemoveEmoji: {
transformers: [
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.emoji",
],
event: "events.reactionRemoveEmoji",
},
handleMessageUpdate: { transformers: ["transformers.message"], event: "events.messageUpdate" },
handlePresenceUpdate: { transformers: ["transformers.presence"], event: "events.presenceUpdate" },
handleReady: {
transformers: [
"transformers.user",
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
],
event: "events.ready",
},
handleTypingStart: {
transformers: [
"transformers.snowflake",
"transformers.snowflake",
"transformers.snowflake",
"transformers.member",
],
event: "events.typingStart",
},
handleUserUpdate: { transformers: ["transformers.user"], event: "events.botUpdate" },
handleGuildRoleCreate: {
transformers: ["transformers.role", "transformers.snowflake"],
event: "events.roleCreate",
},
handleGuildRoleDelete: {
transformers: ["transformers.snowflake", "transformers.snowflake"],
event: "events.roleDelete",
},
handleGuildRoleUpdate: {
transformers: ["transformers.role", "transformers.snowflake"],
event: "events.roleUpdate",
},
handleVoiceServerUpdate: { transformers: ["transformers.snowflake"], event: "events.voiceServerUpdate" },
handleVoiceStateUpdate: {
transformers: ["transformers.snowflake", "transformers.voiceState"],
event: "events.voiceStateUpdate",
},
handleWebhooksUpdate: {
transformers: ["transformers.snowflake", "transformers.snowflake"],
event: "events.webhooksUpdate",
},
};
export default function FlowChart({ handlerFilter = (handler: string) => true }) {
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height,
};
}
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
const transformers = [];
const events = [];
const initialNodes: Node[] = [
{
id: "baseNode-gateway",
type: "input",
position: { x: 0 * multiplier, y: 0 },
data: { label: "gateway" },
...defaultNodeOptions,
},
{
id: "baseNode-yourCode",
type: "output",
position: { x: 5 * multiplier, y: 0 },
data: { label: "Your Code" },
...defaultNodeOptions,
},
{ id: "baseLineNode-1", type: "baseLineNode", position: { x: 0.85 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-2", type: "baseLineNode", position: { x: 0.85 * multiplier, y: -130 }, data: {} },
{ id: "baseLineNode-3", type: "baseLineNode", position: { x: 4.85 * multiplier, y: 170 }, data: {} },
{ id: "baseLineNode-4", type: "baseLineNode", position: { x: 4.85 * multiplier, y: -130 }, data: {} },
{
id: "baseLineNodeText-1",
type: "baseLineNodeText",
position: { x: 0 * multiplier, y: -130 },
data: { label: "Gateway" },
},
{
id: "baseLineNodeText-2",
type: "baseLineNodeText",
position: { x: 1 * multiplier, y: -130 },
data: { label: "Bot" },
},
{
id: "baseLineNodeText-3",
type: "baseLineNodeText",
position: { x: 5 * multiplier, y: -130 },
data: { label: "Your Code" },
},
{
id: "baseNode-handleDiscordPayload",
position: { x: 1 * multiplier, y: 0 },
data: { label: "Handle discord payload" },
...defaultNodeOptions,
},
];
const initialEdges: Edge[] = [
{ id: "baseEdge-1", source: "baseNode-gateway", target: "baseNode-handleDiscordPayload" },
{ id: "baseEdge-3", source: "baseNode-g-1", target: "baseNode-g-2" },
{ id: "baseEdge-4", source: "baseNode-g-2", target: "baseNode-handleDiscordPayload" },
{
id: "baseLine-1",
source: "baseLineNode-1",
target: "baseLineNode-2",
style: { stroke: "blue", strokeDasharray: 20 },
},
{
id: "baseLine-2",
source: "baseLineNode-3",
target: "baseLineNode-4",
style: { stroke: "blue", strokeDasharray: 20 },
},
];
//@ts-ignore
for (const [index, handler] of Object.keys(handlers).filter(handlerFilter).entries()) {
initialNodes.push({
id: handler,
position: {
x: 2 * multiplier,
y: index * (height + 10) - Object.keys(handlers).filter(handlerFilter).length * ((height + 10) / 2) +
height / 2,
},
data: { label: handler.slice(6) },
...defaultNodeOptions,
});
initialEdges.push({
id: `handleDiscordPayload-${handler}`,
source: "baseNode-handleDiscordPayload",
target: handler,
});
if (!events.find((e) => e === handlers[handler].event) && handlers[handler].event) {
events.push(handlers[handler].event);
initialEdges.push({
id: `${handlers[handler].event}-yourCode`,
source: handlers[handler].event,
target: "baseNode-yourCode",
});
}
for (const transformer of handlers[handler].transformers) {
if (!transformers.find((t) => t === transformer) && transformer) transformers.push(transformer);
if (!initialEdges.find((edge) => edge.id === `${handler}-${transformer}`) && transformer) {
initialEdges.push({ id: `${handler}-${transformer}`, source: handler, target: transformer });
}
if (
!initialEdges.find((edge) => edge.id === `${transformer}-${handlers[handler].event}`) && handlers[handler].event
) {
initialEdges.push({
id: `${transformer}-${handlers[handler].event}`,
source: transformer,
target: handlers[handler].event,
});
}
}
}
//@ts-ignore
for (const [index, transformer] of transformers.entries()) {
initialNodes.push({
id: transformer,
position: {
x: 3 * multiplier,
y: index * (height + 10) - transformers.length * ((height + 10) / 2) + height / 2,
},
data: { label: transformer.slice(13) },
...defaultNodeOptions,
});
}
//@ts-ignore
for (const [index, event] of events.entries()) {
initialNodes.push({
id: event,
position: { x: 4 * multiplier, y: index * (height + 10) - events.length * ((height + 10) / 2) + height / 2 },
data: { label: event.slice(7) },
...defaultNodeOptions,
});
}
initialNodes.unshift(
{
id: "handlers",
type: "group",
position: {
x: 1.925 * multiplier,
y: -Object.keys(handlers).filter(handlerFilter).length * ((height + 10) / 2) - 45,
},
data: { label: "" },
style: {
height: `${Object.keys(handlers).filter(handlerFilter).length * (height + 10) + 75}px`,
width: `${multiplier * 0.9}px`,
borderColor: "rgba(0,0,0,0.25)",
},
draggable: false,
},
{
id: "baseLineNodeText-4",
type: "baseLineNodeText",
position: {
x: 2 * multiplier,
y: -Object.keys(handlers).filter(handlerFilter).length * ((height + 10) / 2) - ((height + 10) / 2),
},
data: { label: "Handlers" },
draggable: false,
},
{
id: "transformers",
type: "group",
position: { x: 2.925 * multiplier, y: -transformers.length * ((height + 10) / 2) - 45 },
data: { label: "" },
style: {
height: `${transformers.length * (height + 10) + 75}px`,
width: `${multiplier * 0.9}px`,
borderColor: "rgba(0,0,0,0.25)",
},
draggable: false,
},
{
id: "baseLineNodeText-5",
type: "baseLineNodeText",
position: { x: 3 * multiplier, y: -transformers.length * ((height + 10) / 2) - ((height + 10) / 2) },
data: { label: "Transformers" },
draggable: false,
},
{
id: "events",
type: "group",
position: { x: 3.925 * multiplier, y: -events.length * ((height + 10) / 2) - 45 },
data: { label: "" },
style: {
height: `${events.length * (height + 10) + 75}px`,
width: `${multiplier * 0.9}px`,
borderColor: "rgba(0,0,0,0.25)",
},
draggable: false,
},
{
id: "baseLineNodeText-6",
type: "baseLineNodeText",
position: { x: 4 * multiplier, y: -events.length * ((height + 10) / 2) - ((height + 10) / 2) },
data: { label: "Event" },
draggable: false,
},
);
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const [handlerIndex, setHandlerIndex] = useState(0);
const [userClick, setUserClick] = useState(false);
const nodeMouseHandler: NodeMouseHandler = (_, node, userTrigger = true) => {
if (userTrigger) setUserClick(true);
if (node.id.split("-")[0] === "baseNode") {
edges.forEach((e) => {
if (e.id.startsWith("baseLine")) return;
e.animated = true;
e.style = { stroke: "blue" };
});
setEdges([...edges]);
return;
}
if (Object.keys(handlers).find((h) => handlers[h].event === node.id)) {
const handlerName = Object.keys(handlers).find((h) => handlers[h].event === node.id);
const handler = handlers[handlerName];
edges.forEach((e) => {
if (e.id.startsWith("baseLine")) return;
if (e.id.split("-")[0] === "baseEdge") {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (e.id.split("-")[0] === "handleDiscordPayload" && e.id.split("-")[1] === handlerName) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (e.id.split("-")[0] === handlerName && handler.transformers.includes(e.id.split("-")[1])) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (handler.transformers.includes(e.id.split("-")[0]) && e.id.split("-")[1] === handler.event) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (e.id.split("-")[0] === handler.event && e.id.split("-")[1] === "yourCode") {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
e.animated = false;
e.style = { opacity: 0.3 };
});
setEdges([...edges]);
return;
}
if (Object.keys(handlers).find((h) => handlers[h].transformers.includes(node.id))) {
edges.forEach((e) => {
if (e.id.startsWith("baseLine")) return;
if (e.id.split("-")[0] === "baseEdge") {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (
e.id.split("-")[0] === "handleDiscordPayload" &&
Object.keys(handlers).filter((h) => handlers[h].transformers.includes(node.id)).includes(e.id.split("-")[1])
) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (
Object.keys(handlers).filter((h) => handlers[h].transformers.includes(node.id)).includes(
e.id.split("-")[0],
) && e.id.split("-")[1] === node.id
) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (e.id.split("-")[0] === node.id) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
e.animated = false;
e.style = { opacity: 0.3 };
});
setEdges([...edges]);
return;
}
if (handlers[node.id]) {
const handler = handlers[node.id];
edges.forEach((e) => {
if (e.id.startsWith("baseLine")) return;
if (e.id.split("-")[0] === "baseEdge") {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (e.id.split("-")[0] === "handleDiscordPayload" && e.id.split("-")[1] === node.id) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (e.id.split("-")[0] === node.id && handler.transformers.includes(e.id.split("-")[1])) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (handler.transformers.includes(e.id.split("-")[0]) && e.id.split("-")[1] === handler.event) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
if (e.id.split("-")[0] === handler.event) {
e.animated = true;
e.style = { stroke: "blue" };
return;
}
e.animated = false;
e.style = { opacity: 0.3 };
});
setEdges([...edges]);
return;
}
edges.forEach((e) => {
if (e.id.startsWith("baseLine")) return;
e.animated = false;
e.style = {};
});
setEdges([...edges]);
};
useEffect(() => {
const interval = setInterval(() => {
const randomIndex = Math.round((Object.keys(handlers).filter(handlerFilter).length - 1) * Math.random());
if (!userClick) {
nodeMouseHandler(undefined, { id: Object.keys(handlers).filter(handlerFilter)[randomIndex] }, false);
}
setHandlerIndex(randomIndex);
}, 1000);
return () => clearInterval(interval);
}, [userClick]);
useEffect(() => {
if (userClick) {
const timeout = setTimeout(() => {
setUserClick(false);
}, 10000);
return () => clearTimeout(timeout);
}
}, [userClick]);
return (
<>
<div
style={{
width: windowDimensions.width >= 997
? `${
(100 *
((windowDimensions.width - 300 -
(windowDimensions.width >= 1620 ? (windowDimensions.width - 1620) * 0.5 : 0)) /
windowDimensions.width) - 2) * widthMultiplier
}vw`
: "95vw",
height: "50vh",
}}
>
<ReactFlow
nodes={nodes}
edges={edges}
defaultEdgeOptions={{ focusable: false }}
onNodeDoubleClick={nodeMouseHandler}
onNodeClick={nodeMouseHandler}
onClick={(e) => {
//@ts-ignore
if (e.target.className === "react-flow__pane") nodeMouseHandler(e, { id: " - ", data: { label: " - " } });
}}
nodeTypes={{
baseLineNode: () => (
<div style={{ height: "1px", width: "20px" }}>
<Handle
type="target"
position={Position.Bottom}
style={{ background: "rgba(0,0,0,0)", borderColor: "rgba(0,0,0,0)" }}
/>
<Handle
type="source"
position={Position.Top}
style={{ background: "rgba(0,0,0,0)", borderColor: "rgba(0,0,0,0)" }}
/>
</div>
),
baseLineNodeText: (n) => (
<div style={{ textAlign: "center", width: defaultNodeOptions.style.width }}>
<h3>{n.data.label}</h3>
</div>
),
}}
fitView
>
<Controls />
<Background />
</ReactFlow>
</div>
</>
);
}
+4 -4
View File
@@ -1,10 +1,10 @@
import React from "react";
import clsx from "clsx";
import Layout from "@theme/Layout";
import Link from "@docusaurus/Link";
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
import styles from "./index.module.css";
import Layout from "@theme/Layout";
import clsx from "clsx";
import React from "react";
import HomepageFeatures from "../components/HomepageFeatures";
import styles from "./index.module.css";
function HomepageHeader() {
const { siteConfig } = useDocusaurusContext();
@@ -127,14 +127,14 @@ const gateway = createGatewayManager({
});
```
**Basic Keys**
#### Basic Keys
- `EVENT_HANDLER_SECRET_KEY` is from your configs that will be used to make sure requests sent to your event handler
process are indeed from you.
- `DISCORD_TOKEN` if you can't figure this out, this guide isn't for you. Please find another.
- `INTENTS` pass in a number or a string of intents. Autocomplete/type-safety is provided for strings :)
**Powerful Keys**
#### Powerful Keys
If your bot is going to be run on one process, you can re-use the data that discord gave you to connect.
+30
View File
@@ -0,0 +1,30 @@
/**
* Creating a sidebar enables you to:
- create an ordered group of docs
- render a sidebar for each doc of that group
- provide next/previous navigation
The sidebars can be generated from the filesystem, or explicitly defined here.
Create as many sidebars as you want.
*/
// @ts-check
/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
// By default, Docusaurus generates a sidebar from the docs folder structure
tutorial: [{ type: "autogenerated", dirName: "." }],
// But you can create a sidebar manually
/*
tutorialSidebar: [
{
type: 'category',
label: 'Tutorial',
items: ['hello'],
},
],
*/
};
module.exports = sidebars;