mirror of
https://github.com/discordeno/discordeno.git
synced 2026-09-17 08:47:22 +00:00
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:
@@ -6,9 +6,13 @@ name: Deploy Docs Site
|
||||
on:
|
||||
# Triggers the workflow on push or pull request events but only for the "main" branch
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
branches: ["main"]
|
||||
paths:
|
||||
- "site/**"
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
branches: ["main"]
|
||||
paths:
|
||||
- "site/**"
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
@@ -23,6 +27,7 @@ jobs:
|
||||
# This workflow contains a single job called "build"
|
||||
build:
|
||||
# The type of runner that the job will run on
|
||||
name: Build Docusaurus
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
@@ -48,6 +53,7 @@ jobs:
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.event_name != 'pull_request'
|
||||
steps:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: Test Docusaurus build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "site/**"
|
||||
|
||||
jobs:
|
||||
test-deploy:
|
||||
name: Test deployment
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 14.x
|
||||
cache: npm
|
||||
cache-dependency-path: site/package-lock.json
|
||||
- name: Test build
|
||||
working-directory: site
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
@@ -0,0 +1,38 @@
|
||||
const handlers: {
|
||||
[index: string]: any;
|
||||
} = {};
|
||||
|
||||
const topDirs = ["./handlers"];
|
||||
|
||||
const readDir = async (dirname: string, onContent: (content: string) => void) => {
|
||||
const files: Deno.DirEntry[] = [];
|
||||
for (const dirEntry of Deno.readDirSync(dirname)) {
|
||||
files.push(dirEntry);
|
||||
}
|
||||
await Promise.all(
|
||||
files.map(async (file) => {
|
||||
if (file.isFile) {
|
||||
const content = await Deno.readTextFile(dirname + "/" + file.name);
|
||||
onContent(content);
|
||||
return;
|
||||
}
|
||||
if (file.isDirectory) await readDir(`${dirname}/${file.name}`, onContent);
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
await Promise.all(topDirs.map((topDir) =>
|
||||
readDir(topDir, (content) => {
|
||||
const handler = content.match(/export function [A-z]+\(/g);
|
||||
if (handler === null) return;
|
||||
const transformers = content.match(/bot.transformers.[A-z]+\(/g);
|
||||
const event = content.match(/bot.events.[A-z]+\(/);
|
||||
|
||||
handlers[handler.map((handler) => handler.slice(16, -1))[0]] = {
|
||||
transformers: transformers === null ? [] : transformers.map((result) => result.slice(4, -1)),
|
||||
event: event === null ? undefined : event.map((result) => result.slice(4, -1))[0],
|
||||
};
|
||||
})
|
||||
));
|
||||
|
||||
console.log(handlers);
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
-1
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Frequently Asked Questions
|
||||
@@ -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
|
||||
@@ -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
@@ -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
|
||||
},
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
Generated
+6095
-4920
File diff suppressed because it is too large
Load Diff
+11
-8
@@ -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": {
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user