Main logic + prettier graphing, no graph solver yet
This commit is contained in:
38
winx-serve/src/App.css
Normal file
38
winx-serve/src/App.css
Normal 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
12
winx-serve/src/App.js
Normal 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;
|
||||
149
winx-serve/src/CustomGraph.js
Normal file
149
winx-serve/src/CustomGraph.js
Normal 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;
|
||||
128
winx-serve/src/CustomNodeComponent.js
Normal file
128
winx-serve/src/CustomNodeComponent.js
Normal 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
174
winx-serve/src/Data.js
Normal 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
23
winx-serve/src/index.css
Normal 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
12
winx-serve/src/index.js
Normal 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>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user