diff --git a/aiida_worktree/web/backend/app/api.py b/aiida_worktree/web/backend/app/api.py
index b1b5c6d6..5dc2f8aa 100644
--- a/aiida_worktree/web/backend/app/api.py
+++ b/aiida_worktree/web/backend/app/api.py
@@ -23,8 +23,35 @@ async def read_root() -> dict:
return {"message": "Welcome to your todo list."}
+@app.get("/worktree-data")
+async def read_worktree_data():
+ from fastapi import HTTPException
+ from aiida_worktree.cli.query_worktree import WorkTreeQueryBuilder
+
+ try:
+ relationships = {}
+ builder = WorkTreeQueryBuilder()
+ query_set = builder.get_query_set(
+ relationships=relationships,
+ # filters=filters,
+ # order_by={order_by: order_dir},
+ # past_days=past_days,
+ # limit=limit,
+ )
+ project = ["pk", "uuid", "state", "ctime", "mtime", "process_label"]
+ projected = builder.get_projected(query_set, projections=project)
+ # pop headers
+ projected.pop(0)
+ data = []
+ for p in projected:
+ data.append({project[i]: p[i] for i in range(len(project))})
+ return data
+ except KeyError:
+ raise HTTPException(status_code=404, detail=f"Worktree {id} not found")
+
+
@app.get("/worktree/{id}")
-async def read_item(id: str):
+async def read_worktree_item(id: int):
from fastapi import HTTPException
from .utils import worktree_to_json
@@ -38,6 +65,6 @@ async def read_item(id: str):
return
wtdata = deserialize_unsafe(wtdata)
content = worktree_to_json(wtdata)
- return {"id": id, "content": content}
+ return content
except KeyError:
raise HTTPException(status_code=404, detail=f"Worktree {id} not found")
diff --git a/aiida_worktree/web/frontend/package-lock.json b/aiida_worktree/web/frontend/package-lock.json
index 25aabf24..d069dec5 100644
--- a/aiida_worktree/web/frontend/package-lock.json
+++ b/aiida_worktree/web/frontend/package-lock.json
@@ -8,6 +8,8 @@
"name": "worktree",
"version": "0.1.0",
"dependencies": {
+ "@fortawesome/free-solid-svg-icons": "^6.5.1",
+ "@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@@ -20,6 +22,8 @@
"elkjs": "^0.8.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-paginate": "^8.2.0",
+ "react-router-dom": "^6.20.1",
"react-scripts": "5.0.1",
"rete": "^2.0.2",
"rete-area-3d-plugin": "^2.0.3",
@@ -2424,6 +2428,52 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@fortawesome/fontawesome-common-types": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
+ "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==",
+ "hasInstallScript": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/fontawesome-svg-core": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz",
+ "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==",
+ "hasInstallScript": true,
+ "peer": true,
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.5.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-solid-svg-icons": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz",
+ "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==",
+ "hasInstallScript": true,
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.5.1"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/react-fontawesome": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
+ "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
+ "dependencies": {
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "@fortawesome/fontawesome-svg-core": "~1 || ~6",
+ "react": ">=16.3"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.13",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
@@ -3288,6 +3338,14 @@
}
}
},
+ "node_modules/@remix-run/router": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz",
+ "integrity": "sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q==",
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
"node_modules/@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -14639,6 +14697,17 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
+ "node_modules/react-paginate": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/react-paginate/-/react-paginate-8.2.0.tgz",
+ "integrity": "sha512-sJCz1PW+9PNIjUSn919nlcRVuleN2YPoFBOvL+6TPgrH/3lwphqiSOgdrLafLdyLDxsgK+oSgviqacF4hxsDIw==",
+ "dependencies": {
+ "prop-types": "^15"
+ },
+ "peerDependencies": {
+ "react": "^16 || ^17 || ^18"
+ }
+ },
"node_modules/react-refresh": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
@@ -14647,6 +14716,36 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-router": {
+ "version": "6.20.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.20.1.tgz",
+ "integrity": "sha512-ccvLrB4QeT5DlaxSFFYi/KR8UMQ4fcD8zBcR71Zp1kaYTC5oJKYAp1cbavzGrogwxca+ubjkd7XjFZKBW8CxPA==",
+ "dependencies": {
+ "@remix-run/router": "1.13.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/react-router-dom": {
+ "version": "6.20.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.20.1.tgz",
+ "integrity": "sha512-npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==",
+ "dependencies": {
+ "@remix-run/router": "1.13.1",
+ "react-router": "6.20.1"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.8",
+ "react-dom": ">=16.8"
+ }
+ },
"node_modules/react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
@@ -19556,6 +19655,36 @@
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz",
"integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA=="
},
+ "@fortawesome/fontawesome-common-types": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz",
+ "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A=="
+ },
+ "@fortawesome/fontawesome-svg-core": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.5.1.tgz",
+ "integrity": "sha512-MfRCYlQPXoLlpem+egxjfkEuP9UQswTrlCOsknus/NcMoblTH2g0jPrapbcIb04KGA7E2GZxbAccGZfWoYgsrQ==",
+ "peer": true,
+ "requires": {
+ "@fortawesome/fontawesome-common-types": "6.5.1"
+ }
+ },
+ "@fortawesome/free-solid-svg-icons": {
+ "version": "6.5.1",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.5.1.tgz",
+ "integrity": "sha512-S1PPfU3mIJa59biTtXJz1oI0+KAXW6bkAb31XKhxdxtuXDiUIFsih4JR1v5BbxY7hVHsD1RKq+jRkVRaf773NQ==",
+ "requires": {
+ "@fortawesome/fontawesome-common-types": "6.5.1"
+ }
+ },
+ "@fortawesome/react-fontawesome": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz",
+ "integrity": "sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw==",
+ "requires": {
+ "prop-types": "^15.8.1"
+ }
+ },
"@humanwhocodes/config-array": {
"version": "0.11.13",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
@@ -20179,6 +20308,11 @@
"source-map": "^0.7.3"
}
},
+ "@remix-run/router": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.13.1.tgz",
+ "integrity": "sha512-so+DHzZKsoOcoXrILB4rqDkMDy7NLMErRdOxvzvOKb507YINKUP4Di+shbTZDhSE/pBZ+vr7XGIpcOO0VLSA+Q=="
+ },
"@rollup/plugin-babel": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.1.tgz",
@@ -28282,11 +28416,36 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
},
+ "react-paginate": {
+ "version": "8.2.0",
+ "resolved": "https://registry.npmjs.org/react-paginate/-/react-paginate-8.2.0.tgz",
+ "integrity": "sha512-sJCz1PW+9PNIjUSn919nlcRVuleN2YPoFBOvL+6TPgrH/3lwphqiSOgdrLafLdyLDxsgK+oSgviqacF4hxsDIw==",
+ "requires": {
+ "prop-types": "^15"
+ }
+ },
"react-refresh": {
"version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A=="
},
+ "react-router": {
+ "version": "6.20.1",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.20.1.tgz",
+ "integrity": "sha512-ccvLrB4QeT5DlaxSFFYi/KR8UMQ4fcD8zBcR71Zp1kaYTC5oJKYAp1cbavzGrogwxca+ubjkd7XjFZKBW8CxPA==",
+ "requires": {
+ "@remix-run/router": "1.13.1"
+ }
+ },
+ "react-router-dom": {
+ "version": "6.20.1",
+ "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.20.1.tgz",
+ "integrity": "sha512-npzfPWcxfQN35psS7rJgi/EW0Gx6EsNjfdJSAk73U/HqMEJZ2k/8puxfwHFgDQhBGmS3+sjnGbMdMSV45axPQw==",
+ "requires": {
+ "@remix-run/router": "1.13.1",
+ "react-router": "6.20.1"
+ }
+ },
"react-scripts": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz",
diff --git a/aiida_worktree/web/frontend/package.json b/aiida_worktree/web/frontend/package.json
index d66fd9e8..ddbe0733 100644
--- a/aiida_worktree/web/frontend/package.json
+++ b/aiida_worktree/web/frontend/package.json
@@ -3,6 +3,8 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@fortawesome/free-solid-svg-icons": "^6.5.1",
+ "@fortawesome/react-fontawesome": "^0.2.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@@ -15,6 +17,8 @@
"elkjs": "^0.8.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-paginate": "^8.2.0",
+ "react-router-dom": "^6.20.1",
"react-scripts": "5.0.1",
"rete": "^2.0.2",
"rete-area-3d-plugin": "^2.0.3",
diff --git a/aiida_worktree/web/frontend/src/App.css b/aiida_worktree/web/frontend/src/App.css
index 74b5e053..aad786db 100644
--- a/aiida_worktree/web/frontend/src/App.css
+++ b/aiida_worktree/web/frontend/src/App.css
@@ -1,9 +1,10 @@
.App {
text-align: center;
+ display: flex;
}
.App-logo {
- height: 40vmin;
+ height: 5vmin;
pointer-events: none;
}
@@ -36,3 +37,150 @@
transform: rotate(360deg);
}
}
+
+/* Home page sidebar Menu */
+
+.sidebar {
+ width: 50px; /* Initial width */
+ height: 100vh;
+ background-color: #333;
+ padding-top: 20px;
+ position: fixed;
+ transition: width 0.3s;
+ overflow: hidden;
+}
+
+.sidebar:hover {
+ width: 200px; /* Expanded width */
+}
+
+.logo-container {
+ width: 50px; /* Logo container width */
+ text-align: center;
+}
+
+.sidebar img {
+ width: 30px; /* Adjust as per your logo's dimensions */
+ cursor: pointer;
+}
+
+.sidebar nav ul {
+ list-style-type: none;
+ padding: 0;
+ margin-top: 20px;
+}
+
+.sidebar nav ul li {
+ padding: 10px;
+}
+
+.sidebar:hover nav ul li {
+ opacity: 1;
+}
+
+.sidebar nav ul li a {
+ color: white;
+ text-decoration: none;
+}
+
+.content {
+ margin-left: 50px; /* Match the initial width of the sidebar */
+ padding: 20px;
+ transition: margin-left 0.3s;
+}
+
+.sidebar:hover ~ .content {
+ margin-left: 200px; /* Match the expanded width of the sidebar */
+}
+
+/* ... existing styles ... */
+
+.sidebar ul li a {
+ display: flex;
+ align-items: center;
+ color: white;
+ text-decoration: none;
+}
+
+.sidebar ul li a span {
+ margin-left: 10px;
+ display: none; /* Hide text labels by default */
+}
+
+.sidebar:hover ul li a span {
+ display: inline; /* Show text labels on hover */
+}
+
+/* Icon styles */
+.sidebar nav ul li a .fa-icon {
+ min-width: 20px; /* Ensure icons have space */
+}
+
+/* Pagination styles */
+.pagination {
+ display: flex;
+ list-style-type: none;
+ justify-content: center;
+ padding: 0;
+}
+
+.pagination li {
+ margin: 0 5px;
+}
+
+.pagination li a {
+ border: 1px solid #007bff;
+ padding: 5px 10px;
+ text-decoration: none;
+ color: #007bff;
+ border-radius: 5px;
+}
+
+.pagination li a:hover {
+ background-color: #007bff;
+ color: white;
+}
+
+.pagination .active a {
+ background-color: #007bff;
+ color: white;
+}
+
+/* Table styles */
+.table {
+ width: 100%;
+ border-collapse: collapse;
+ margin: 25px 0;
+ font-size: 0.9em;
+ font-family: sans-serif;
+ min-width: 400px;
+ box-shadow: 0 0 20px rgba(0, 0, 0, 0.15);
+}
+
+.table thead tr {
+ background-color: #009879;
+ color: #ffffff;
+ text-align: left;
+}
+
+.table th,
+.table td {
+ padding: 12px 15px;
+}
+
+.table tbody tr {
+ border-bottom: 1px solid #dddddd;
+}
+
+.table tbody tr:nth-of-type(even) {
+ background-color: #f3f3f3;
+}
+
+.table tbody tr:last-of-type {
+ border-bottom: 2px solid #009879;
+}
+
+.table tbody tr.active-row {
+ font-weight: bold;
+ color: #009879;
+}
diff --git a/aiida_worktree/web/frontend/src/App.js b/aiida_worktree/web/frontend/src/App.js
new file mode 100644
index 00000000..15f575d0
--- /dev/null
+++ b/aiida_worktree/web/frontend/src/App.js
@@ -0,0 +1,40 @@
+import React from 'react';
+import { BrowserRouter as Router, Route, Link, Routes } from 'react-router-dom';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faHome, faTree, faDotCircle, faCog } from '@fortawesome/free-solid-svg-icons';
+import Home from './components/Home';
+import WorkTree from './components/WorkTree';
+import Node from './components/Node';
+import WorkTreeGraph from './components/WorkTreeGraph'; // Import the component for the detail page
+import Settings from './components/Settings'; // Import your Settings component
+import './App.css';
+
+function App() {
+ return (
+
PK | +Created | +Process Label | +State | +
---|---|---|---|
+ {item.pk} + | +{item.ctime} | +{item.process_label} | +{item.state} | +
State: {worktreeData.state}
+Create Time: {worktreeData.ctime}
+ {/* Render more data as needed */} +