From f6ca0f923a229e428d455e3e18119a4f3055b9a1 Mon Sep 17 00:00:00 2001 From: shoofle Date: Tue, 24 Sep 2024 10:56:04 -0400 Subject: [PATCH] stable andd prepping for the vite changeover --- client/package-lock.json | 107 ++++ client/package.json | 6 + client/src/App.css | 58 +- client/src/App.js | 12 +- client/src/Landing.jsx | 57 -- client/src/apiTools.jsx | 16 +- client/src/index.css | 13 - client/src/index.js | 1 - client/src/landing/GraphRender.jsx | 29 + client/src/landing/Landing.css | 30 + client/src/landing/Landing.jsx | 49 ++ client/src/landing/PageList.jsx | 26 + .../src/{EditPage.jsx => page/PageEdit.jsx} | 70 ++- client/src/{ => page}/PageView.jsx | 34 +- client/src/page/Pages.css | 31 ++ db/the_big_db.db/dbs/default/data-wal | Bin 461472 -> 626272 bytes db/the_big_db.db/dbs/default/stats.json | 2 +- db/the_big_db.db/dbs/default/wallog | Bin 461504 -> 626304 bytes server/graphStuff.js | 26 + server/package-lock.json | 519 ++++++++++++++++++ server/package.json | 5 + server/server.js | 23 +- 22 files changed, 929 insertions(+), 185 deletions(-) delete mode 100644 client/src/Landing.jsx delete mode 100644 client/src/index.css create mode 100644 client/src/landing/GraphRender.jsx create mode 100644 client/src/landing/Landing.css create mode 100644 client/src/landing/Landing.jsx create mode 100644 client/src/landing/PageList.jsx rename client/src/{EditPage.jsx => page/PageEdit.jsx} (60%) rename client/src/{ => page}/PageView.jsx (50%) create mode 100644 client/src/page/Pages.css create mode 100644 server/graphStuff.js diff --git a/client/package-lock.json b/client/package-lock.json index f0ed26eb..31f81b10 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -9,14 +9,20 @@ "version": "0.1.0", "dependencies": { "@libsql/client": "^0.11.0", + "@react-sigma/core": "^4.0.3", "@tanstack/react-query": "^5.56.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "graphology": "^0.25.4", + "graphology-layout": "^0.6.1", + "graphology-layout-force": "^0.2.4", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.26.2", "react-scripts": "^5.0.1", + "react-sigma": "^1.2.35", + "sigma": "^3.0.0-beta.29", "web-vitals": "^2.1.4" } }, @@ -3461,6 +3467,16 @@ } } }, + "node_modules/@react-sigma/core": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@react-sigma/core/-/core-4.0.3.tgz", + "integrity": "sha512-/y/U1GH18xjGYMWNYXXqHGJ+8tHf+e4z1i0gNSm9iuhch8sGFJooO3VfyPJlBox42Wl4/gCapQhOHAfVW0pRtw==", + "peerDependencies": { + "graphology": "^0.25.4", + "react": "^18.0.0", + "sigma": "^3.0.0-beta.24" + } + }, "node_modules/@remix-run/router": { "version": "1.19.2", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.2.tgz", @@ -9246,6 +9262,55 @@ "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, + "node_modules/graphology": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/graphology/-/graphology-0.25.4.tgz", + "integrity": "sha512-33g0Ol9nkWdD6ulw687viS8YJQBxqG5LWII6FI6nul0pq6iM2t5EKquOTFDbyTblRB3O9I+7KX4xI8u5ffekAQ==", + "dependencies": { + "events": "^3.3.0", + "obliterator": "^2.0.2" + }, + "peerDependencies": { + "graphology-types": ">=0.24.0" + } + }, + "node_modules/graphology-layout": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/graphology-layout/-/graphology-layout-0.6.1.tgz", + "integrity": "sha512-m9aMvbd0uDPffUCFPng5ibRkb2pmfNvdKjQWeZrf71RS1aOoat5874+DcyNfMeCT4aQguKC7Lj9eCbqZj/h8Ag==", + "dependencies": { + "graphology-utils": "^2.3.0", + "pandemonium": "^2.4.0" + }, + "peerDependencies": { + "graphology-types": ">=0.19.0" + } + }, + "node_modules/graphology-layout-force": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/graphology-layout-force/-/graphology-layout-force-0.2.4.tgz", + "integrity": "sha512-NYZz0YAnDkn5pkm30cvB0IScFoWGtbzJMrqaiH070dYlYJiag12Oc89dbVfaMaVR/w8DMIKxn/ix9Bqj+Umm9Q==", + "dependencies": { + "graphology-utils": "^2.4.2" + }, + "peerDependencies": { + "graphology-types": ">=0.19.0" + } + }, + "node_modules/graphology-types": { + "version": "0.24.7", + "resolved": "https://registry.npmjs.org/graphology-types/-/graphology-types-0.24.7.tgz", + "integrity": "sha512-tdcqOOpwArNjEr0gNQKCXwaNCWnQJrog14nJNQPeemcLnXQUUGrsCWpWkVKt46zLjcS6/KGoayeJfHHyPDlvwA==", + "peer": true + }, + "node_modules/graphology-utils": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/graphology-utils/-/graphology-utils-2.5.2.tgz", + "integrity": "sha512-ckHg8MXrXJkOARk56ZaSCM1g1Wihe2d6iTmz1enGOz4W/l831MBCKSayeFQfowgF8wd+PQ4rlch/56Vs/VZLDQ==", + "peerDependencies": { + "graphology-types": ">=0.23.0" + } + }, "node_modules/gzip-size": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz", @@ -12913,6 +12978,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mnemonist": { + "version": "0.39.8", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.8.tgz", + "integrity": "sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==", + "dependencies": { + "obliterator": "^2.0.1" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -13242,6 +13315,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==" + }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -13370,6 +13448,14 @@ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" }, + "node_modules/pandemonium": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/pandemonium/-/pandemonium-2.4.1.tgz", + "integrity": "sha512-wRqjisUyiUfXowgm7MFH2rwJzKIr20rca5FsHXCMNm1W5YPP1hCtrZfgmQ62kP7OZ7Xt+cR858aB28lu5NX55g==", + "dependencies": { + "mnemonist": "^0.39.2" + } + }, "node_modules/param-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", @@ -15378,6 +15464,18 @@ } } }, + "node_modules/react-sigma": { + "version": "1.2.35", + "resolved": "https://registry.npmjs.org/react-sigma/-/react-sigma-1.2.35.tgz", + "integrity": "sha512-amjKjaQusefDp8dD9er3wE/lfubSQT5fJSRF4SsS0LjxRue4bpSapAQ1WpmSM6nQEgawbrKel+bQBmatl7MAIw==", + "engines": { + "node": ">=8.0" + }, + "peerDependencies": { + "react": ">=15.3", + "react-dom": ">=15.3" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -16222,6 +16320,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/sigma": { + "version": "3.0.0-beta.29", + "resolved": "https://registry.npmjs.org/sigma/-/sigma-3.0.0-beta.29.tgz", + "integrity": "sha512-3VpLIEnuDiZbO7XPnsyyUwUoTOI9u5aDq9nIPvc/eO3FHE/z7P7gCvfmAu2JB1635gZSLwt39mvDpYTXZ8+jaQ==", + "dependencies": { + "events": "^3.3.0", + "graphology-utils": "^2.5.2" + } + }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", diff --git a/client/package.json b/client/package.json index 74ecfa39..4758315c 100644 --- a/client/package.json +++ b/client/package.json @@ -4,14 +4,20 @@ "private": true, "dependencies": { "@libsql/client": "^0.11.0", + "@react-sigma/core": "^4.0.3", "@tanstack/react-query": "^5.56.2", "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "graphology": "^0.25.4", + "graphology-layout": "^0.6.1", + "graphology-layout-force": "^0.2.4", "react": "^18.3.1", "react-dom": "^18.3.1", "react-router-dom": "^6.26.2", "react-scripts": "^5.0.1", + "react-sigma": "^1.2.35", + "sigma": "^3.0.0-beta.29", "web-vitals": "^2.1.4" }, "scripts": { diff --git a/client/src/App.css b/client/src/App.css index 4223ef20..2962eebb 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -1,50 +1,18 @@ -.App { - text-align: center; - padding-left: 60vmin; - padding-right: 60vmin; - background-color: #282c34; +body { + background: rgb(0,131,77); + background: radial-gradient(circle, rgba(0,131,77,1) 0%, rgba(17,66,0,1) 100%); + font-family: sans-serif; } -.App-logo { - height: 10vmin; - pointer-events: none; +button { + border-radius: 1rem; + padding: 1rem; + margin: 1rem; } -@media (prefers-reduced-motion: no-preference) { - .App-logo { - animation: App-logo-spin infinite 20s linear; - } -} - -.App-header { - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -.Page-contents { - text-align: left; - padding: 1em; - border: 1px solid black; - width: 100%; -} -.Page-contents pre { - width: 100%; +a { + color: lightslategrey; } +a:visited { + color: slategray; +} \ No newline at end of file diff --git a/client/src/App.js b/client/src/App.js index d928df36..80424b25 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -1,8 +1,10 @@ -import { BrowserRouter, Routes, Route } from 'react-router-dom'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query' -import Landing from './Landing.jsx' -import PageView from './PageView.jsx' -import EditPage from './EditPage.jsx' +import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import Landing from './landing/Landing.jsx' +import PageView from './page/PageView.jsx' +import PageEdit from './page/PageEdit.jsx' + +import './App.css' const queryClient = new QueryClient(); @@ -13,7 +15,7 @@ function App() { }/> }/> - }/> + }/> diff --git a/client/src/Landing.jsx b/client/src/Landing.jsx deleted file mode 100644 index cc3111ff..00000000 --- a/client/src/Landing.jsx +++ /dev/null @@ -1,57 +0,0 @@ -import logo from './logo.svg'; -import './App.css'; - -import { useNavigate, Link } from 'react-router-dom' -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; - -import { apiUrl, fetchPageList, postNewPage } from './apiTools.jsx'; -import { useFixLinks } from './clientStuff.jsx'; - -function Landing() { - const queryClient = useQueryClient(); - const navigate = useNavigate(); - const noLoad = useFixLinks(); - const { isPending, error, data } = useQuery({ // fetch the currrent values - queryKey: ['pages'], - queryFn: fetchPageList - }) - - const makeNewPage = useMutation({ // for changing the value when we're done with it - mutationFn: () => postNewPage() - .catch((error) => { console.log("got an error", error.json()) }), - onSettled: async (data, error, variables) => { - // Invalidate and navigate to the new page - await queryClient.invalidateQueries({ queryKey: ['pages'] }); - navigate(`/${data}/edit`); - }, - }); - - return ( -
-
- logo -

Welcome to the forest!

-

This is some random stuff I added!

- { isPending ? - "Loading..." : - (error ? -
{error}
- : -
    - { - data.map((row) => -
  • - page {row} -
  • - ) - } -
- ) - } - -
-
- ); -} - -export default Landing; \ No newline at end of file diff --git a/client/src/apiTools.jsx b/client/src/apiTools.jsx index bf4293c6..980b409e 100644 --- a/client/src/apiTools.jsx +++ b/client/src/apiTools.jsx @@ -1,3 +1,5 @@ +import Graph from 'graphology'; + // This is wrapper functtions to do requests to the api, from the frontend. export const apiUrl = "http://127.0.0.1:3001" @@ -42,4 +44,16 @@ export async function deletePage(id) { headers: {'Content-Type': 'application/json'}, ...defaults }) - } \ No newline at end of file +} + +export async function fetchGraph() { + return fetch(`${apiUrl}/graph`, { + method: 'GET', + ...defaults + }).then((res) => res.json()) + .then((serialized) => { + const graph = new Graph(); + graph.import(serialized); + return graph; + }) +} \ No newline at end of file diff --git a/client/src/index.css b/client/src/index.css deleted file mode 100644 index ec2585e8..00000000 --- a/client/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/client/src/index.js b/client/src/index.js index d563c0fb..5d4fdcfa 100644 --- a/client/src/index.js +++ b/client/src/index.js @@ -1,6 +1,5 @@ import React from 'react'; import ReactDOM from 'react-dom/client'; -import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; diff --git a/client/src/landing/GraphRender.jsx b/client/src/landing/GraphRender.jsx new file mode 100644 index 00000000..106edee6 --- /dev/null +++ b/client/src/landing/GraphRender.jsx @@ -0,0 +1,29 @@ +import { SigmaContainer } from "@react-sigma/core"; +import "@react-sigma/core/lib/react-sigma.min.css"; + +import { useQuery } from '@tanstack/react-query'; +import { fetchGraph } from '../apiTools.jsx'; + +import ForceSupervisor from 'graphology-layout-force/worker'; + + +export default function GraphRender() { + const { isPending, error, data } = useQuery({ // fetch the currrent values + queryKey: ['graph'], + queryFn: fetchGraph + }); + + let outputStuff; + if (isPending) outputStuff = "Loading..."; + else if (error) outputStuff = `Error encountered: ${error}`; + else outputStuff = ( + + ); + + if (data) (new ForceSupervisor(data, {allowInvalidContainer: true})).start(); + return outputStuff; +} \ No newline at end of file diff --git a/client/src/landing/Landing.css b/client/src/landing/Landing.css new file mode 100644 index 00000000..0b0be1c0 --- /dev/null +++ b/client/src/landing/Landing.css @@ -0,0 +1,30 @@ + +.landing-page { + padding-left:10rem; + padding-right: 10rem; + padding-top: 3rem; + color: white; +} +.landing-page header { + text-align: right; + width: 100%; +} +.landing-page header hr { + width: 60%; + margin-inline-start: auto; + margin-inline-end: 0; + color: white; +} +.landing-container { + display: grid; + width: 100%; + grid-template-columns: repeat(3, 1fr); +} +.landing-section { + margin: 1rem; + padding: 1rem; + border-radius: 1rem; + color: white; + background: rgba(10,66,30, 0.75); +} + diff --git a/client/src/landing/Landing.jsx b/client/src/landing/Landing.jsx new file mode 100644 index 00000000..9b768f11 --- /dev/null +++ b/client/src/landing/Landing.jsx @@ -0,0 +1,49 @@ +import { useNavigate, Link } from 'react-router-dom' +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; + +import { fetchPageList, postNewPage } from '../apiTools.jsx'; +import { useFixLinks } from '../clientStuff.jsx'; + +import PageList from './PageList.jsx'; +import GraphRender from './GraphRender.jsx'; + +import './Landing.css' + +function Landing() { + const queryClient = useQueryClient(); + const navigate = useNavigate(); + + const makeNewPage = useMutation({ // for changing the value when we're done with it + mutationFn: () => postNewPage() + .catch((error) => { console.log("got an error", error.json()) }), + onSettled: async (data, error, variables) => { + // Invalidate and navigate to the new page + await queryClient.invalidateQueries({ queryKey: ['pages'] }); + navigate(`/${data}/edit`); + }, + }); + + return ( +
+
+

Welcome to the forest.

+
+
+
+
+ +
+
+ +
+
+
+
+
+
+
+
+ ); +} + +export default Landing; \ No newline at end of file diff --git a/client/src/landing/PageList.jsx b/client/src/landing/PageList.jsx new file mode 100644 index 00000000..52320485 --- /dev/null +++ b/client/src/landing/PageList.jsx @@ -0,0 +1,26 @@ +import { useQuery } from '@tanstack/react-query'; +import { fetchPageList } from '../apiTools.jsx'; +import { useFixLinks } from '../clientStuff.jsx'; + +export default function PageList({pages, ...props}) { + const noLoad = useFixLinks(); + const { isPending, error, data } = useQuery({ // fetch the currrent values + queryKey: ['pages'], + queryFn: fetchPageList + }); + + let outputContents = ""; + if (isPending) outputContents = "Loading..."; + else if (error) outputContents = `Error encountered: ${error}`; + else outputContents = ( +
    + { data.map(({id, title}) => +
  1. + {title} +
  2. + )} +
+ ); + + return outputContents; +} diff --git a/client/src/EditPage.jsx b/client/src/page/PageEdit.jsx similarity index 60% rename from client/src/EditPage.jsx rename to client/src/page/PageEdit.jsx index 024ac25a..e7f23b58 100644 --- a/client/src/EditPage.jsx +++ b/client/src/page/PageEdit.jsx @@ -1,10 +1,8 @@ -import logo from './logo.svg'; -import { App } from './App.js'; -import './App.css'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useParams, useNavigate } from 'react-router-dom'; -import { useState } from 'react'; -import { apiUrl, fetchPage, postPage, deletePage } from './apiTools.jsx'; +import { apiUrl, fetchPage, postPage, deletePage } from '../apiTools.jsx'; + +import './Pages.css'; function PageView() { const queryClient = useQueryClient(); @@ -57,40 +55,40 @@ function PageView() { } return ( -
-
- logo -
-

- {pagenumber}. - +
+

+ {pagenumber}.  + -

-

- { ready ? - <> -
-
-            
- - - - : -
- { fetchQuery.isPending ? "Loading..." : JSON.stringify(fetchQuery.error) } + +
+ +
+ { ready ? + <> +
+
           
- } + + + + : +
+ { fetchQuery.isPending ? "Loading..." : JSON.stringify(fetchQuery.error) } +
+ }
); diff --git a/client/src/PageView.jsx b/client/src/page/PageView.jsx similarity index 50% rename from client/src/PageView.jsx rename to client/src/page/PageView.jsx index 6392963e..2fefc43e 100644 --- a/client/src/PageView.jsx +++ b/client/src/page/PageView.jsx @@ -1,12 +1,9 @@ -import logo from './logo.svg'; -import { App } from './App.js'; -import './App.css'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { useParams, useNavigate } from 'react-router-dom'; -import { useState } from 'react'; -import { apiUrl, fetchPage, postPage } from './apiTools.jsx'; -import { useFixLinks } from './clientStuff.jsx'; +import { apiUrl, fetchPage, postPage } from '../apiTools.jsx'; +import { useFixLinks } from '../clientStuff.jsx'; +import './Pages.css'; function PageView() { const queryClient = useQueryClient(); @@ -25,26 +22,25 @@ function PageView() { if (data) [the_id, page_title, page_text, page_html] = data; return ( -
-
- logo -
-

{pagenumber}. {ready ? (page_title || " ") : "..."}

-
+
+
+
+

{pagenumber}. {ready ? (page_title || " ") : "..."}

+
+
+
{ ready ?
: -
- { isPending ? "Loading..." : JSON.stringify(error) } -
+ (isPending ? "Loading..." : JSON.stringify(error)) } - - -
+ +
+
); } diff --git a/client/src/page/Pages.css b/client/src/page/Pages.css new file mode 100644 index 00000000..779683a4 --- /dev/null +++ b/client/src/page/Pages.css @@ -0,0 +1,31 @@ + +.page-container { + padding-left:10rem; + padding-right: 10rem; + padding-top: 3rem; + color: white; +} +.page-container header { + text-align: right; + width: 100%; +} +.page-container header hr { + width: 60%; + margin-inline-start: auto; + margin-inline-end: 0; + color: white; +} + +.page-contents { + text-align: left; + background: rgba(17,66,0); + margin: 1rem; + padding: 1rem; + border-radius: 1rem; + +} +.page-contents pre { + width: 100%; + white-space: normal; +} + diff --git a/db/the_big_db.db/dbs/default/data-wal b/db/the_big_db.db/dbs/default/data-wal index e1d393b922c2774f7c55e30ae3e7a1d900640df0..3868be43796ac8838dcff7e3d17c58bdfcdb2897 100644 GIT binary patch literal 626272 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 YDM@HmMXZE~1(|H1aW?#+0{RjBf03;QH~;_u delta 23 ecmaDbM{U7WnT8g|7N!>F7M2#)7Pc+y3%CGnst5)E diff --git a/db/the_big_db.db/dbs/default/stats.json b/db/the_big_db.db/dbs/default/stats.json index 2b8aadc9..eb38cc0b 100644 --- a/db/the_big_db.db/dbs/default/stats.json +++ b/db/the_big_db.db/dbs/default/stats.json @@ -1 +1 @@ -{"id":"7de13931-444c-4dd2-a19a-5cd1e70b7f36","rows_written":112,"rows_read":2745,"storage_bytes_used":12288,"write_requests_delegated":0,"current_frame_no":111,"top_query_threshold":3,"top_queries":[{"rows_written":2,"rows_read":1,"query":"\ncreate table if not exists renders (\n id integer primary key,\n title varchar(255),\n description text\n)\n"},{"rows_written":0,"rows_read":4,"query":"select id from pages"},{"rows_written":0,"rows_read":5,"query":"select id from pages"},{"rows_written":1,"rows_read":4,"query":"\nalter table pages \nadd column html text\n"},{"rows_written":0,"rows_read":6,"query":"\nselect p.id from pages p where not exists (select r.id from renders r where p.id = r.id)\n"},{"rows_written":0,"rows_read":10,"query":"select id from pages"},{"rows_written":0,"rows_read":11,"query":"select id from pages"},{"rows_written":0,"rows_read":12,"query":"select id from pages"},{"rows_written":0,"rows_read":13,"query":"select id from pages"},{"rows_written":0,"rows_read":14,"query":"select id from pages"}],"slowest_query_threshold":0,"slowest_queries":[{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":1},{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":2},{"elapsed_ms":1,"query":"\nalter table pages \nadd column html text\n","rows_written":1,"rows_read":4},{"elapsed_ms":1,"query":"\ncreate table if not exists renders (\n id integer primary key,\n title varchar(255),\n description text\n)\n","rows_written":2,"rows_read":1},{"elapsed_ms":1,"query":"insert into pages (title, description) values (?, ?) returning id","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"replace into pages (id, title, description, html) values (?, ?, ?, ?)","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"select * from pages where id=@val","rows_written":0,"rows_read":1},{"elapsed_ms":1,"query":"select count(*) as num_pages from pages","rows_written":0,"rows_read":1},{"elapsed_ms":7,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1}],"embedded_replica_frames_replicated":0,"query_count":1006,"query_latency":98084} \ No newline at end of file +{"id":"7de13931-444c-4dd2-a19a-5cd1e70b7f36","rows_written":149,"rows_read":10979,"storage_bytes_used":20480,"write_requests_delegated":0,"current_frame_no":151,"top_query_threshold":15,"top_queries":[{"rows_written":0,"rows_read":15,"query":"select id, html from pages"},{"rows_written":0,"rows_read":15,"query":"select id, title from pages"},{"rows_written":0,"rows_read":16,"query":"select id, html from pages"},{"rows_written":0,"rows_read":16,"query":"select id, title from pages"},{"rows_written":0,"rows_read":17,"query":"select id, html from pages"},{"rows_written":0,"rows_read":17,"query":"select id, title from pages"},{"rows_written":0,"rows_read":18,"query":"select id, html from pages"},{"rows_written":0,"rows_read":18,"query":"select id, title from pages"},{"rows_written":0,"rows_read":19,"query":"select id, html from pages"},{"rows_written":0,"rows_read":19,"query":"select id, title from pages"}],"slowest_query_threshold":0,"slowest_queries":[{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":1},{"elapsed_ms":0,"query":"select title from pages","rows_written":0,"rows_read":2},{"elapsed_ms":1,"query":"\nalter table pages \nadd column html text\n","rows_written":1,"rows_read":4},{"elapsed_ms":1,"query":"\ncreate table if not exists renders (\n id integer primary key,\n title varchar(255),\n description text\n)\n","rows_written":2,"rows_read":1},{"elapsed_ms":1,"query":"insert into pages (title, description) values (?, ?) returning id","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"replace into pages (id, title, description, html) values (?, ?, ?, ?)","rows_written":1,"rows_read":1},{"elapsed_ms":1,"query":"select * from pages where id=@val","rows_written":0,"rows_read":1},{"elapsed_ms":1,"query":"select count(*) as num_pages from pages","rows_written":0,"rows_read":1},{"elapsed_ms":7,"query":"replace into pages (id, title, description) values (?, ?, ?)","rows_written":1,"rows_read":1}],"embedded_replica_frames_replicated":0,"query_count":1820,"query_latency":153654} \ No newline at end of file diff --git a/db/the_big_db.db/dbs/default/wallog b/db/the_big_db.db/dbs/default/wallog index 7fa83dab343ff5e13f799f7aaed5658599f7b3df..0b67998bbc18447f3cbfd19758305a36f81110c3 100644 GIT binary patch literal 626304 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

}eG1_PR51gebyya2qwJiI{j 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 HNAUjv)8wN) delta 35 qcmZpet9D?j%mfX_f=10&O~zJDrdCbnR!x>xP1aUTwym1%)42f6^9nZr diff --git a/server/graphStuff.js b/server/graphStuff.js new file mode 100644 index 00000000..2925fa28 --- /dev/null +++ b/server/graphStuff.js @@ -0,0 +1,26 @@ +const { JSDOM } = require("jsdom"); +const graphology = require("graphology"); +const { circular } = require('graphology-layout'); + +function graphFromList(allTheStuff) { + const graph = new graphology.Graph(); + + for (const [id, html] of allTheStuff) { + graph.addNode(id); + } + + for (const [id, html] of allTheStuff) { + const { document } = (new JSDOM(html)).window; + const links = document.querySelectorAll('a'); + links.forEach((link) => { + const referent = link.href.replace("/",""); + graph.mergeEdge(id, referent); + }); + } + + circular.assign(graph); + + return graph; +} + +module.exports = { graphFromList: graphFromList }; \ No newline at end of file diff --git a/server/package-lock.json b/server/package-lock.json index 817619bd..be8c3c60 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -10,6 +10,11 @@ "license": "ISC", "dependencies": { "express": "^4.21.0", + "graphology": "^0.25.4", + "graphology-layout": "^0.6.1", + "graphology-layout-force": "^0.2.4", + "graphology-layout-forceatlas2": "^0.10.1", + "jsdom": "^25.0.0", "nodemon": "^3.1.5", "showdown": "^2.1.0" } @@ -26,6 +31,38 @@ "node": ">= 0.6" } }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -43,6 +80,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -151,6 +193,17 @@ "fsevents": "~2.3.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "9.5.0", "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", @@ -196,6 +249,29 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, + "node_modules/cssstyle": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.1.0.tgz", + "integrity": "sha512-h66W1URKpBS5YMI/V8PyXvTMFT8SupJ1IzoIV8IeBC/ji8WVmrO8dGlTi+2dh6whmdk6BiKJLD/ZBkhWbcg6nA==", + "dependencies": { + "rrweb-cssom": "^0.7.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -204,6 +280,11 @@ "ms": "2.0.0" } }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", @@ -220,6 +301,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -250,6 +339,17 @@ "node": ">= 0.8" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", @@ -282,6 +382,14 @@ "node": ">= 0.6" } }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, "node_modules/express": { "version": "4.21.0", "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", @@ -351,6 +459,19 @@ "node": ">= 0.8" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -428,6 +549,66 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graphology": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/graphology/-/graphology-0.25.4.tgz", + "integrity": "sha512-33g0Ol9nkWdD6ulw687viS8YJQBxqG5LWII6FI6nul0pq6iM2t5EKquOTFDbyTblRB3O9I+7KX4xI8u5ffekAQ==", + "dependencies": { + "events": "^3.3.0", + "obliterator": "^2.0.2" + }, + "peerDependencies": { + "graphology-types": ">=0.24.0" + } + }, + "node_modules/graphology-layout": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/graphology-layout/-/graphology-layout-0.6.1.tgz", + "integrity": "sha512-m9aMvbd0uDPffUCFPng5ibRkb2pmfNvdKjQWeZrf71RS1aOoat5874+DcyNfMeCT4aQguKC7Lj9eCbqZj/h8Ag==", + "dependencies": { + "graphology-utils": "^2.3.0", + "pandemonium": "^2.4.0" + }, + "peerDependencies": { + "graphology-types": ">=0.19.0" + } + }, + "node_modules/graphology-layout-force": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/graphology-layout-force/-/graphology-layout-force-0.2.4.tgz", + "integrity": "sha512-NYZz0YAnDkn5pkm30cvB0IScFoWGtbzJMrqaiH070dYlYJiag12Oc89dbVfaMaVR/w8DMIKxn/ix9Bqj+Umm9Q==", + "dependencies": { + "graphology-utils": "^2.4.2" + }, + "peerDependencies": { + "graphology-types": ">=0.19.0" + } + }, + "node_modules/graphology-layout-forceatlas2": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/graphology-layout-forceatlas2/-/graphology-layout-forceatlas2-0.10.1.tgz", + "integrity": "sha512-ogzBeF1FvWzjkikrIFwxhlZXvD2+wlY54lqhsrWprcdPjopM2J9HoMweUmIgwaTvY4bUYVimpSsOdvDv1gPRFQ==", + "dependencies": { + "graphology-utils": "^2.1.0" + }, + "peerDependencies": { + "graphology-types": ">=0.19.0" + } + }, + "node_modules/graphology-types": { + "version": "0.24.7", + "resolved": "https://registry.npmjs.org/graphology-types/-/graphology-types-0.24.7.tgz", + "integrity": "sha512-tdcqOOpwArNjEr0gNQKCXwaNCWnQJrog14nJNQPeemcLnXQUUGrsCWpWkVKt46zLjcS6/KGoayeJfHHyPDlvwA==", + "peer": true + }, + "node_modules/graphology-utils": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/graphology-utils/-/graphology-utils-2.5.2.tgz", + "integrity": "sha512-ckHg8MXrXJkOARk56ZaSCM1g1Wihe2d6iTmz1enGOz4W/l831MBCKSayeFQfowgF8wd+PQ4rlch/56Vs/VZLDQ==", + "peerDependencies": { + "graphology-types": ">=0.23.0" + } + }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -480,6 +661,17 @@ "node": ">= 0.4" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -495,6 +687,72 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -562,6 +820,50 @@ "node": ">=0.12.0" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==" + }, + "node_modules/jsdom": { + "version": "25.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-25.0.0.tgz", + "integrity": "sha512-OhoFVT59T7aEq75TVw9xxEfkXgacpqAhQaYgP9y/fDqWQCMB/b1H66RfmPm/MaeaAIU9nDwMOVTlPN51+ao6CQ==", + "dependencies": { + "cssstyle": "^4.0.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.12", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.7.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.4", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^2.11.2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -627,6 +929,14 @@ "node": "*" } }, + "node_modules/mnemonist": { + "version": "0.39.8", + "resolved": "https://registry.npmjs.org/mnemonist/-/mnemonist-0.39.8.tgz", + "integrity": "sha512-vyWo2K3fjrUw8YeeZ1zF0fy6Mu59RHokURlld8ymdUPjMlD9EC9ov1/YPqTgqRvUN9nTr3Gqfz29LYAmu0PHPQ==", + "dependencies": { + "obliterator": "^2.0.1" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -696,6 +1006,11 @@ "node": ">=0.10.0" } }, + "node_modules/nwsapi": { + "version": "2.2.12", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz", + "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w==" + }, "node_modules/object-inspect": { "version": "1.13.2", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", @@ -707,6 +1022,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obliterator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/obliterator/-/obliterator-2.0.4.tgz", + "integrity": "sha512-lgHwxlxV1qIg1Eap7LgIeoBWIMFibOjbrYPIPJZcI1mmGAI2m3lNYpK12Y+GBdPQ0U1hRwSord7GIaawz962qQ==" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -718,6 +1038,25 @@ "node": ">= 0.8" } }, + "node_modules/pandemonium": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/pandemonium/-/pandemonium-2.4.1.tgz", + "integrity": "sha512-wRqjisUyiUfXowgm7MFH2rwJzKIr20rca5FsHXCMNm1W5YPP1hCtrZfgmQ62kP7OZ7Xt+cR858aB28lu5NX55g==", + "dependencies": { + "mnemonist": "^0.39.2" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -754,11 +1093,24 @@ "node": ">= 0.10" } }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==" + }, "node_modules/pstree.remy": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==" }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.13.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", @@ -773,6 +1125,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -806,6 +1163,16 @@ "node": ">=8.10.0" } }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/rrweb-cssom": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz", + "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -830,6 +1197,17 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/semver": { "version": "7.6.3", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", @@ -974,6 +1352,11 @@ "node": ">=4" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1001,6 +1384,31 @@ "nodetouch": "bin/nodetouch.js" } }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -1018,6 +1426,14 @@ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==" }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -1026,6 +1442,15 @@ "node": ">= 0.8" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1041,6 +1466,100 @@ "engines": { "node": ">= 0.8" } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz", + "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==", + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" } } } diff --git a/server/package.json b/server/package.json index 71a0abd8..4053197c 100644 --- a/server/package.json +++ b/server/package.json @@ -15,6 +15,11 @@ "license": "ISC", "dependencies": { "express": "^4.21.0", + "graphology": "^0.25.4", + "graphology-layout": "^0.6.1", + "graphology-layout-force": "^0.2.4", + "graphology-layout-forceatlas2": "^0.10.1", + "jsdom": "^25.0.0", "nodemon": "^3.1.5", "showdown": "^2.1.0" } diff --git a/server/server.js b/server/server.js index 23502708..414128c1 100644 --- a/server/server.js +++ b/server/server.js @@ -1,6 +1,7 @@ const express = require('express'); const showdown = require('showdown'); const { query } = require('./dbHelper.js'); +const { graphFromList } = require('./graphStuff.js'); const port = process.env.PORT || 3001; // Use the port provided by the host or default to 3000 @@ -20,26 +21,26 @@ app.listen(port, () => { }); app.get('/pages', (req, res) => { - query('select id from pages', []) + query('select id, title from pages', []) .then((r) => r.rows) - .then((row) => row.map(([id]) => id)) - .then((ids) => res.status(200).json(ids)) + .then((row) => row.map(([id, title]) => {return {"id": id, "title": title};})) + .then((pages) => res.status(200).json(pages)) .catch((error) => res.status(500).json({"error": error})); }); app.post('/page/new', (req, res) => { query('insert into pages (title, description) values (?, ?) returning id', ["new page", "this page is new!"]) - .then((r) => r.rows[0][0]) - .then((row) => res.status(200).json({id: row})) + .then((r) => r.rows[0]) + .then((row) => res.status(200).json({id: row[0]})) .catch((error) => res.status(500).json({"error": error})) }); app.get('/page/:id', (req, res) => { query('select * from pages where id=?', [req.params.id]) .then((r) => { - if (r.rows.length == 0) return res.status(404).json({"error": "page not found in db"}); - return r.rows[0]; + if (r.rows.length == 0) res.status(404).json({"error": "page not found in db"}); + else return r.rows[0]; }).then((row) => res.status(200).json(row)) .catch((error) => res.status(500).json({"error": error})); }); @@ -57,3 +58,11 @@ app.delete('/page/:id', (req, res) => { .then(() => res.status(200).json({id: req.params.id})) .catch((error) => res.status(500).json({"error": error})) }) + +app.get('/graph', (req, res) => { + query('select id, html from pages', []) + .then((r) => r.rows) + .then((stuff) => graphFromList(stuff)) + .then((graph) => res.json(graph)) + .catch((error) => res.status(500).json({"error": error})); +}); \ No newline at end of file