Main logic + prettier graphing, no graph solver yet

This commit is contained in:
2024-05-01 20:20:39 +03:00
parent f02375948d
commit 9580da34cc
29 changed files with 19747 additions and 169 deletions

38
winx-serve/src/App.css Normal file
View File

@@ -0,0 +1,38 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
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);
}
}

12
winx-serve/src/App.js Normal file
View File

@@ -0,0 +1,12 @@
import React from 'react';
import CustomGraph from './CustomGraph';
function App() {
return (
<div className="App" style={{height: 100 + 'vh'}}>
<CustomGraph />
</div>
);
}
export default App;

View File

@@ -0,0 +1,149 @@
import React, { useEffect } from 'react';
import ReactFlow, { Controls, Background, useNodesState, useEdgesState } from 'react-flow-renderer';
import CustomNodeComponent from './CustomNodeComponent';
import {ReactFlowProvider} from "reactflow";
import {jsonData} from './Data.js';
const nodeTypes = {
customNode: CustomNodeComponent,
};
function CustomGraph() {
const [nodes, setNodes, onNodesChange] = useNodesState([]);
const [edges, setEdges, onEdgesChange] = useEdgesState([]);
useEffect(() => {
const loadedNodes = [];
const loadedEdges = [];
let yOffset = 100;
jsonData.forEach((pkg, index) => {
const pkgId = `pkg-${pkg.name}`;
loadedNodes.push({
id: pkgId,
type: 'customNode',
position: { x: 100, y: yOffset * index },
data: { label: `Package: ${pkg.name}`, ...pkg }
});
pkg.interfaces.forEach((iface, iIndex) => {
const ifaceId = `iface-${iface.name}`;
loadedNodes.push({
id: ifaceId,
type: 'customNode',
position: { x: 300, y: yOffset * (index + 1 + iIndex) },
data: { label: `Interface: ${iface.name}`, ...iface }
});
loadedEdges.push({
id: `e-${pkgId}-${ifaceId}`,
source: pkgId,
target: ifaceId,
type: 'simplebezier',
animated: true,
});
iface.functions.forEach((func, fIndex) => {
const funcId = `func-${iface.name}-${func.name}`;
loadedNodes.push({
id: funcId,
type: 'customNode',
position: { x: 500, y: yOffset * (index + 2 + iIndex + fIndex) },
data: { label: `${func.name}()`, ...func }
});
loadedEdges.push({
id: `e-${ifaceId}-${funcId}`,
source: ifaceId,
target: funcId,
type: 'simplebezier',
animated: true
});
});
});
pkg.specifications.forEach((spec, sIndex) => {
const specId = `spec-${spec.name}`;
loadedNodes.push({
id: specId,
type: 'customNode',
position: { x: 300, y: yOffset * (index + 1 + sIndex) },
data: { label: `Specification: ${spec.name}`, ...spec }
});
if (spec.implemented_interface) {
const interfaceId = `iface-${spec.implemented_interface}`;
loadedEdges.push({
id: `e-${interfaceId}-${specId}`,
source: interfaceId,
target: specId,
type: 'simplebezier',
animated: true
});
}
loadedEdges.push({
id: `e-${pkgId}-${specId}`,
source: pkgId,
target: specId,
type: 'simplebezier',
animated: true,
style: { stroke: '#000', strokeWidth: 4 }
});
spec.functions.forEach((func, fIndex) => {
const funcId = `func-${spec.name}-${func.name}`;
loadedNodes.push({
id: funcId,
type: 'customNode',
position: { x: 500, y: yOffset * (index + 2 + sIndex + fIndex) },
data: { label: `${func.name}()`, ...func },
});
if (func.implemented_interface) {
const interfaceId = `iface-${func.implemented_interface}`;
loadedEdges.push({
id: `e-${interfaceId}-${funcId}`,
source: interfaceId,
target: funcId,
type: 'simplebezier',
animated: true
});
}
loadedEdges.push({
id: `e-${specId}-${funcId}`,
source: specId,
target: funcId,
type: 'simplebezier',
animated: true,
style: { stroke: '#000', strokeWidth: 4 }
});
});
});
});
console.log(loadedEdges)
setNodes(loadedNodes);
setEdges(loadedEdges);
}, [setNodes, setEdges]);
return (
<div style={{ height: 100+'vh', width: 100 + '%' }}>
<ReactFlowProvider>
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
nodeTypes={nodeTypes}
fitView>
<Controls />
<Background />
</ReactFlow>
</ReactFlowProvider>
</div>
);
}
export default CustomGraph;

View File

@@ -0,0 +1,128 @@
import React from 'react';
import {Handle} from "reactflow";
const CustomNodeComponent = ({data}) => {
return (
<div className="flex">
{data.inputTypes && (<div className="content-start bg-amber-400 flex-1 h-1/2 p-1 rounded-l">
<div>
<div className="flex">
<img className="content-center mr-2" alt="inputCog" src="/input.png"
style={{width: 20 + 'px', height: 20 + 'px'}}/>
<strong className="content-center">Input: </strong>
</div>
{data.inputTypes.map((input, idx) => (
<div className="text-gray-700" key={idx}>{input.type} {input.identifier}</div>))}
</div>
</div>
)}
<div className="flex flex-col innerBody rounded-bl-lg rounded-tr-lg divide-y sans-font"
style={{
backgroundColor: data.importance === 'critical' ? '#F59975' : '#01C6C9',
}}>
<div>
<div className="access rounded-tr-lg m-0 text-center" style={{
backgroundColor: data.access_modifier === "public" ? "#00aa88" : data.access_modifier === "private" ? "red" : "#FF8C00"
}}>
{data.access_modifier && (<div
className="p-1 text-xl font-bold text-white">{data.access_modifier.toUpperCase()}</div>)}
</div>
</div>
<div className="p-3 m-0">
<Handle type="target" position="top" style={{borderRadius: 0}}/>
<div className="header">
<div className="flex justify-between" style={{fontWeight: 'bold', marginBottom: '5px'}}>
<div className="content-center text-2xl">
{data.label}
</div>
</div>
</div>
<div className="general">
<div className="flex">
<div className="content-center mr-2">
<img src="/cog.png" alt="cog" style={{width: 20 + 'px', height: 20 + 'px'}}/>
</div>
<span className="content-center">
{data.implemented_interface || 'None'}
</span>
</div>
</div>
{data.requirements && (<div>
<strong>Requirements:</strong>
{data.requirements.map((requirement, idx) => (<div className="text-gray-700" key={idx}>
<span className="text-xl font-bold">
{requirement.name}
</span>
{requirement.annotations && requirement.annotations.map((annotation, index) => (
<div key={index}>
<span className="fade-in-out font-mono text-red-700">
{annotation.importance === "critical" ? "!" : ""}
</span>
<span style={{
color: annotation.importance === "critical" ? "red" : "green"
}}>
{annotation.importance.toUpperCase()} {annotation.name}
</span>
</div>))}
</div>))}
</div>)}
<div className="specs">
{data.specificationEntries && (<div>
<strong>Specifications:</strong>
{data.specificationEntries.map((entry, idx) => (
<div key={idx}>{entry.key}: {entry.value}</div>))}
</div>)}
</div>
<Handle type="source" position="bottom" style={{borderRadius: 0}}/>
</div>
</div>
{data.returnTypes && (<div className="flex flex-col m-0 justify-between">
<div>
<div className="outerBody">
<span className="fade-in-out font-mono text-7xl text-red-700">
{data.importance === "critical" ? "!" : ""}
</span>
</div>
</div>
<div className="bg-amber-400 p-1 rounded-r">
<div className="flex">
<img className="content-center mr-1" alt="outputCog" src="/output.png"
style={{width: 20 + 'px', height: 20 + 'px'}}/>
<strong className="content-center">Output: </strong>
</div>
{data.returnTypes.map((ret, idx) => (
<div className="text-gray-700 m-1" key={idx}>{ret.type} {ret.identifier}</div>))}
</div>
</div>
)}
</div>);
};
export default CustomNodeComponent;

174
winx-serve/src/Data.js Normal file
View File

@@ -0,0 +1,174 @@
export const jsonData = [ {
"name" : "Database",
"interfaces" : [ {
"name" : "Database",
"functions" : [ {
"name" : "GetUserList",
"access_modifier" : "public",
"implemented_interface" : "none",
"importance" : "optional",
"inputTypes" : [ {
"type" : "FLOAT",
"identifier" : "x"
}, {
"type" : "STRING",
"identifier" : "ag"
} ],
"returnTypes" : [ {
"type" : "\"CustomDataType\"",
"identifier" : "x"
} ],
"specificationEntries" : [ {
"key" : "ExecTime",
"value" : "\"10s\""
}, {
"key" : "MaxReturnVals",
"value" : "\"10s\""
} ]
} ]
}, {
"name" : "DatabaseAccessImpl",
"functions" : [ {
"name" : "GetUserList",
"access_modifier" : "protected",
"implemented_interface" : "none",
"importance" : "critical",
"inputTypes" : [ {
"type" : "FLOAT",
"identifier" : "x"
}, {
"type" : "STRING",
"identifier" : "ag"
} ],
"returnTypes" : [ {
"type" : "\"CustomDataType\"",
"identifier" : "x"
} ],
"specificationEntries" : [ {
"key" : "ExecTime",
"value" : "\"10s\""
}, {
"key" : "MaxReturnVals",
"value" : "\"10s\""
} ]
} ]
} ],
"specifications" : [ {
"name" : "DatabaseAccess",
"implemented_interface" : "Database",
"requirements" : [ {
"name" : "DatabaseAccessMember",
"annotations" : [ {
"importance" : "optional",
"name" : "UserHasAdminAccess"
}, {
"importance" : "critical",
"name" : "UserIsNotBanned"
} ]
} ],
"results" : [ {
"name" : "DatabaseAdminPanel",
"importance" : "optional"
}, {
"name" : "DatabaseVisualizerPanel",
"importance" : "critical"
}, {
"name" : "Clock",
"importance" : "none"
} ],
"functions" : [ {
"name" : "GetUserList",
"access_modifier" : "public",
"implemented_interface" : "DatabaseAccessImpl",
"importance" : "critical",
"inputTypes" : [ {
"type" : "FLOAT",
"identifier" : "x"
}, {
"type" : "STRING",
"identifier" : "ag"
} ],
"returnTypes" : [ {
"type" : "INT",
"identifier" : "x"
} ],
"specificationEntries" : [ {
"key" : "ExecTime",
"value" : "\"10s\""
}, {
"key" : "MaxReturnVals",
"value" : "\"10s\""
} ]
}, {
"name" : "GetUserdList",
"access_modifier" : "private",
"implemented_interface" : "Database",
"importance" : "optional",
"inputTypes" : [ {
"type" : "FLOAT",
"identifier" : "x"
}, {
"type" : "STRING",
"identifier" : "ag"
} ],
"returnTypes" : [ {
"type" : "INT",
"identifier" : "x"
} ],
"specificationEntries" : [ {
"key" : "ExecTime",
"value" : "\"10s\""
}, {
"key" : "MaxReturnVals",
"value" : "\"10s\""
} ]
}, {
"name" : "GetUserdfList",
"access_modifier" : "public",
"implemented_interface" : "Database",
"importance" : "optional",
"inputTypes" : [ {
"type" : "FLOAT",
"identifier" : "x"
}, {
"type" : "STRING",
"identifier" : "ag"
} ],
"returnTypes" : [ {
"type" : "INT",
"identifier" : "x"
} ],
"specificationEntries" : [ {
"key" : "ExecTime",
"value" : "\"10s\""
}, {
"key" : "MaxReturnVals",
"value" : "\"10s\""
} ]
}, {
"name" : "GetUsesfrList",
"access_modifier" : "private",
"implemented_interface" : "Database",
"importance" : "optional",
"inputTypes" : [ {
"type" : "FLOAT",
"identifier" : "x"
}, {
"type" : "STRING",
"identifier" : "ag"
} ],
"returnTypes" : [ {
"type" : "INT",
"identifier" : "x"
} ],
"specificationEntries" : [ {
"key" : "ExecTime",
"value" : "\"10s\""
}, {
"key" : "MaxReturnVals",
"value" : "\"10s\""
} ]
} ],
"implementedInterface" : "Database"
} ]
} ];

23
winx-serve/src/index.css Normal file
View File

@@ -0,0 +1,23 @@
@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap');
@tailwind base;
@tailwind components;
@tailwind utilities;
@keyframes fadeAnimation {
0%, 100% {
opacity: 1;
}
50% {
opacity: 0;
}
}
.fade-in-out {
animation: fadeAnimation 3s infinite;
}
.sans-font {
font-family: "Open Sans", sans-serif;
font-optical-sizing: auto;
}

12
winx-serve/src/index.js Normal file
View File

@@ -0,0 +1,12 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);