testing DO NOT MERGE #34

Closed
SinusFox wants to merge 18 commits from GitHub-Pages into main
26 changed files with 10836 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
{
"extends": ["next/core-web-vitals", "next/typescript"],
"rules": {
"react/no-unescaped-entities": "off",
"@next/next/no-page-custom-font": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-unused-vars": "off",
"prefer-const": "off"
}
}
+3
View File
@@ -11,6 +11,9 @@ on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Automatically run on Pull Request
pull_request:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
+26
View File
@@ -0,0 +1,26 @@
name: Run Tests
on:
push:
branches: ["main"]
workflow_dispatch:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: '20'
- name: Install dependencies
run: npm install
- name: Run tests
run: npm test
+36
View File
@@ -847,3 +847,39 @@ FodyWeavers.xsd
### VisualStudio Patch ###
# Additional files built by Visual Studio
### Added by npx/npm for Next.JS ###
# dependencies
/node_modules
/.pnp
.pnp.js
.yarn/install-state.gz
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts
+10
View File
@@ -0,0 +1,10 @@
import type { NextApiRequest, NextApiResponse } from 'next';
export default function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
res.status(200).json({ message: 'API is working!' });
} else {
res.status(405).json({ message: 'Method not allowed' });
}
}
+20
View File
@@ -0,0 +1,20 @@
/** @type {import('jest').Config} */
const nextJest = require('next/jest');
const createJestConfig = nextJest({
dir: './',
});
const customJestConfig = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/jest.setup.js'],
moduleNameMapper: {
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
},
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest',
},
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],
};
module.exports = createJestConfig(customJestConfig);
+1
View File
@@ -0,0 +1 @@
import '@testing-library/jest-dom';
+28
View File
@@ -0,0 +1,28 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
/**
* Enable static exports for the App Router.
*
* @see https://nextjs.org/docs/app/building-your-application/deploying/static-exports
*/
output: "export",
/**
* Set base path. This is the slug of your GitHub repository.
*
* @see https://nextjs.org/docs/app/api-reference/next-config-js/basePath
*/
basePath: "/nextjs-github-pages",
/**
* Disable server-based image optimization. Next.js does not support
* dynamic features with static exports.
*
* @see https://nextjs.org/docs/app/api-reference/components/image#unoptimized
*/
images: {
unoptimized: true,
},
};
export default nextConfig;
+9996
View File
File diff suppressed because it is too large Load Diff
+36
View File
@@ -0,0 +1,36 @@
{
"name": "or-tool",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "jest",
"test:watch": "jest --watch"
},
"dependencies": {
"next": "14.2.11",
"react": "^18",
"react-dom": "^18",
"reactjs-popup": "^2.0.6"
},
"devDependencies": {
"@testing-library/jest-dom": "^6.5.0",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/jest": "^29.5.13",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "14.2.11",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"postcss": "^8",
"tailwindcss": "^3.4.1",
"ts-jest": "^29.2.5",
"typescript": "^5"
}
}
+8
View File
@@ -0,0 +1,8 @@
/** @type {import('postcss-load-config').Config} */
const config = {
plugins: {
tailwindcss: {},
},
};
export default config;
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.
Binary file not shown.
+153
View File
@@ -0,0 +1,153 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
--background: #ffffff;
--foreground: #171717;
}
@media (prefers-color-scheme: dark) {
:root {
--background: #0a0a0a;
--foreground: #ededed;
}
}
body {
color: var(--foreground);
background: var(--background);
font-family: Arial, Helvetica, sans-serif;
}
@layer utilities {
.text-balance {
text-wrap: balance;
}
}
.container {
display: flex;
justify-content: space-between;
width: 100%;
}
.header {
font-size: 36px;
text-align: center;
}
.header_box {
flex: 1;
margin: 10px 10px;
padding: 10px;
border-radius: 20px;
border: 20px solid #202020;
background-color: #202020;
}
.header_copyright {
font-size: 16px;
color:#707070;
padding-top: 10px;
}
.button {
border: 2px solid #5353535c;
background-color: #1010105c;
border-radius: 20px;
margin: 10px;
padding: 10px;
}
.button:hover {
border: 2px solid #5353535c;
background-color: #5353535c;
border-radius: 20px;
margin: 10px;
padding: 10px;
}
.button_green {
border: 2px solid #4795475c;
background-color: #247d245c;
border-radius: 20px;
margin: 10px;
padding: 10px;
}
.button_red {
border: 2px solid #9547475c;
background-color: #7d24245c;
border-radius: 20px;
margin: 10px;
padding: 10px;
}
.button_green:hover {
border: 2px solid #4795475c;
background-color: #4795475c;
border-radius: 20px;
margin: 10px;
padding: 10px;
}
.button_red:hover {
border: 2px solid #9547475c;
background-color: #9547475c;
border-radius: 20px;
margin: 10px;
padding: 10px;
}
.box {
width: 100%;
padding: 10px;
height: 20px;
}
.main_div {
flex: 1;
border-width: 0px;
}
.body_box {
flex: 1;
padding: 10px;
width: 100%;
border-radius: 20px;
border: 2px solid #8d8d8d;
background-color: #474747;
font-size: 10;
}
.body_title {
font-size: 20px;
margin: 10px;
}
.text {
margin: 10px;
}
.output_box {
flex: 1;
padding: 10px;
width: 100%;
border-radius: 20px;
border: 2px solid #8d8d8d;
background-color: #4dc3435c;
font-size: 10;
height: fit-content 100%;
}
.popup_bg {
width: 2000px;
padding: 20px;
box-shadow: 0 2px 10px #7c7c7c;
background: black;
}
.popup-overlay {
background: rgba(0, 0, 0, 0.5);
}
+85
View File
@@ -0,0 +1,85 @@
import type { Metadata } from "next";
import Image from "next/image";
import localFont from "next/font/local";
import "./globals.css";
const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
{children}
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<footer className=" flex gap-6 flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://github.com/Spaceholder-Programming/Operations-Research-Tool/wiki"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="https://nextjs.org/icons/file.svg"
alt="File icon"
width={16}
height={16}
/>
Go to our docs
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://github.com/Spaceholder-Programming/Operations-Research-Tool/"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="https://nextjs.org/icons/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
See the source code
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://www.gnu.org/software/glpk/"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="https://nextjs.org/icons/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Powered by GLPK
</a>
</footer>
</div>
</body>
</html>
);
}
+89
View File
@@ -0,0 +1,89 @@
import { MouseEventHandler } from "react";
import Popup from "reactjs-popup";
export function Box({title, placeholder, id}:
{title:string; placeholder:string; id:string}) {
return(
<div className="main_div">
<div className="body_title">
{title}
</div>
<div className="text">
<textarea
className="body_box"
id={id}
wrap="soft"
rows={6}
placeholder={placeholder}
></textarea>
</div>
</div>
);
}
export function Button({title, className, onClickFunc}:
{title:string; className:string|undefined; onClickFunc: MouseEventHandler}) {
return(
<button
className={className}
onClick={onClickFunc}
>
{title}
</button>
);
}
export function Popup_Button({title, className}:
{title:string; className:string|undefined;}) {
return(
<Popup
trigger={<button
className={className}>
{title}
</button>}
position="right center"
modal
nested>
{close => (
<div className="popup_bg">
<button onClick={close}>
&times;
</button>
<div className="header"> {title} </div>
<div className="content">
This is a popup example.
</div>
<div className="actions">
<button className="button" onClick={close}>
Cancel</button>
</div>
</div>
)}
</Popup>
);
}
export function Output({id, text}:
{id:string; text:string}) {
return(
<div className="main_div">
<div className="body_title"
>
Output
</div>
<div className="text">
<p
className="output_box"
id={id}
value={text}>
</p>
</div>
</div>
);
}
+49
View File
@@ -0,0 +1,49 @@
'use client'
import { Box, Button, Output, Popup_Button } from "./modules.tsx";
import { calculate_click, import_click, export_click } from "./scripts.ts"
export default function Home() {
return (
<>
<header className="header">
<div className="title">
<main className="header_box">
Operations Research Tool
<br></br>
<span className="header_copyright">
<i>by Spaceholder Programming</i>
</span>
</main>
</div>
</header>
<Box
title={"Functions"}
placeholder={"Your Functions here"}
id="funcs"/>
<Box
title={"Variables"}
placeholder={"Your Variables here"}
id="vars" />
<Button
title={"Calculate"}
className={"button_green"}
onClickFunc={calculate_click} />
<Popup_Button
title={"Import"}
className={"button"} />
<Popup_Button
title={"Export"}
className={"button"} />
<br></br>
<Output
id="out"
text={"Ergebnis"}/>
<Popup_Button
title="Popup"
className="button"
/>
</>
);
}
+30
View File
@@ -0,0 +1,30 @@
export function test() {
console.log("Dies ist die Testfunktion.");
}
export function calculate_click() {
console.log("Calculating...");
let functions:string = document.getElementById('funcs').value;
let variables:string = document.getElementById('vars').value;
let funcs:string[] = functions.split(/; */);
let vars:string[] = variables.split(/; */);
// Irgend ein Interface
// document.getElementById('out').innerHTML = funcs;
// output.innerHTML = functions.innerHTML;
}
export function import_click() {
console.log("Importing...");
}
export function export_click() {
console.log("Exporting...");
}
+54
View File
@@ -0,0 +1,54 @@
import { NextApiRequest, NextApiResponse } from 'next';
import GLPK from 'glpk.js';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
const { objective, constraints } = req.body;
try {
const glpk = await GLPK();
const options = {
msglev: glpk.GLP_MSG_ALL,
presol: true,
cb: {
call: (progress: any) => console.log(progress),
each: 1
}
};
const problem = {
name: 'LP',
objective: {
direction: objective.direction === 'max' ? glpk.GLP_MAX : glpk.GLP_MIN,
name: 'obj',
vars: objective.vars
},
subjectTo: constraints.map((c: any) => ({
name: c.name,
vars: c.vars,
bnds: {
type: glpk.GLP_UP,
ub: c.bnds.ub,
lb: c.bnds.lb
}
}))
};
const result = glpk.solve(problem, options);
const lpFormat = `\n# Problem Definition\n
name: ${problem.name}\n
# Objective Function\n
${problem.objective.direction === glpk.GLP_MAX ? 'max' : 'min'} ${problem.objective.vars.map((v: any) => `${v.coef} ${v.name}`).join(' + ')}\n
# Constraints\n
${problem.subjectTo.map((c: any) => `${c.vars.map((v: any) => `${v.coef} ${v.name}`).join(' + ')} ${c.bnds.ub ? `<= ${c.bnds.ub}` : ''}`).join('\n')}\n`;
res.status(200).json({ result, lpFormat });
} catch (error) {
console.error('Error processing optimization:', error);
res.status(500).json({ message: 'Error processing optimization', error: error.message });
}
} else {
res.status(405).json({ message: 'Only POST method is allowed' });
}
}
+44
View File
@@ -0,0 +1,44 @@
import { NextApiRequest, NextApiResponse } from 'next';
import GLPK from 'glpk.js';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method === 'POST') {
const { objective, constraints, bounds } = req.body;
if (!objective || !constraints) {
return res.status(400).json({ message: 'Invalid input data. Ensure that "objective" and "constraints" are provided correctly.' });
}
try {
const glpk = await GLPK();
const options = { msglev: glpk.GLP_MSG_ALL, presol: true };
const problem = {
name: 'MIP',
objective: {
direction: objective.direction === 'max' ? glpk.GLP_MAX : glpk.GLP_MIN,
name: 'obj',
vars: objective.vars.map(v => ({ name: v.name, coef: v.coef }))
},
subjectTo: constraints.map(c => ({
name: c.name,
vars: c.vars.map(v => ({ name: v.name, coef: v.coef })),
bnds: {
type: glpk.GLP_UP,
lb: c.bnds.lb,
ub: c.bnds.ub
}
})),
binaries: objective.vars.map(v => v.name),
generals: objective.vars.map(v => v.name)
};
const result = glpk.solve(problem, options);
res.status(200).json({ result });
} catch (error) {
res.status(500).json({ message: 'Error processing optimization', error: error.message });
}
} else {
res.status(405).json({ message: 'Only POST method is allowed' });
}
}
+36
View File
@@ -0,0 +1,36 @@
type VariableLP = { name: string; coef: number };
type ConstraintLP = {
name: string;
vars: VariableLP[];
bnds: { ub: number; lb: number };
};
interface ProblemLP {
objective: {
vars: VariableLP[];
};
constraints: ConstraintLP[];
}
function createProblemLP(
objectiveVars: VariableLP[],
constraints: { name: string; vars: VariableLP[]; ub: number; lb: number }[]
): ProblemLP {
const constraintsFormatted: ConstraintLP[] = constraints.map((constraint) => ({
name: constraint.name,
vars: constraint.vars,
bnds: {
ub: constraint.ub,
lb: constraint.lb
}
}));
const problem: ProblemLP = {
objective: {
vars: objectiveVars
},
constraints: constraintsFormatted
};
return problem;
}
+77
View File
@@ -0,0 +1,77 @@
interface VariableMIP {
name: string;
coef: number;
}
interface Bounds {
type: number;
ub: number;
lb: number;
}
interface ConstraintMIP {
name: string;
vars: VariableMIP[];
bnds: Bounds;
}
interface Options {
mipgap: number;
tmlim: number;
msglev: number;
}
interface Problem {
name: string;
objective: {
direction: "min" | "max";
name: string;
vars: VariableMIP[];
};
constraints: ConstraintMIP[];
binaries?: string[];
generals?: string[];
options: Options;
}
function createProblemMIP(
name: string,
direction: "min" | "max",
objectiveName: string,
objectiveVars: VariableMIP[],
constraints: { name: string; vars: VariableMIP[]; bnds_type: number; ub: number; lb: number }[],
binaries: string[],
generals: string[] = [],
mipgap: number,
tmlim: number,
msglev: number
): Problem {
const constraintsFormatted: ConstraintMIP[] = constraints.map((constraint) => ({
name: constraint.name,
vars: constraint.vars,
bnds: {
type: constraint.bnds_type,
ub: constraint.ub,
lb: constraint.lb
}
}));
const problem: Problem = {
name: name,
objective: {
direction: direction,
name: objectiveName,
vars: objectiveVars
},
constraints: constraintsFormatted,
binaries: binaries.length > 0 ? binaries : undefined,
generals: generals.length > 0 ? generals : undefined,
options: {
mipgap: mipgap,
tmlim: tmlim,
msglev: msglev
}
};
return problem;
}
+19
View File
@@ -0,0 +1,19 @@
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
background: "var(--background)",
foreground: "var(--foreground)",
},
},
},
plugins: [],
};
export default config;
+26
View File
@@ -0,0 +1,26 @@
{
"compilerOptions": {
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}