diff --git a/backend/app/tasks.py b/backend/app/tasks.py index b7dbe64..cf5f6de 100644 --- a/backend/app/tasks.py +++ b/backend/app/tasks.py @@ -109,6 +109,21 @@ def create_environment_task(self, environment_id): # works if capabilities=[["gpu"]]. For simplicity with 'count', we assume generic allocation. # If we want specific indices, device_requests are constructed as above. + # 3. Configure Volumes + volumes = {} + if env.mount_config: + for mount in env.mount_config: + # mount is expected to be a dict from JSONB + host_path = mount.get('host_path') + container_path = mount.get('container_path') + mode = mount.get('mode', 'rw') + + if host_path and container_path: + volumes[host_path] = {'bind': container_path, 'mode': mode} + + if volumes: + container_config['volumes'] = volumes + client.containers.run(**container_config) env.status = "running" diff --git a/frontend/src/index.css b/frontend/src/index.css index d0c45b8..2afbecf 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -20,3 +20,11 @@ backdrop-filter: blur(10px); border: 1px solid rgba(63, 63, 70, 0.5); } + +.scrollbar-hide { + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ +} +.scrollbar-hide::-webkit-scrollbar { + display: none; /* Chrome, Safari and Opera */ +} diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 78512bf..e76a2aa 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -1,8 +1,14 @@ import axios from 'axios'; -import { RefreshCw, Trash2 } from 'lucide-react'; +import { HardDrive, RefreshCw, Trash2, X } from 'lucide-react'; import { useEffect, useState } from 'react'; import Modal from '../components/Modal'; +interface MountConfig { + host_path: string; + container_path: string; + mode: string; +} + interface Environment { id: string; name: string; @@ -11,12 +17,14 @@ interface Environment { ssh_port: number; jupyter_port: number; created_at: string; + mount_config: MountConfig[]; } export default function Dashboard() { const [environments, setEnvironments] = useState([]); const [loading, setLoading] = useState(true); const [deleteId, setDeleteId] = useState(null); + const [selectedVolEnv, setSelectedVolEnv] = useState(null); const fetchEnvironments = async () => { try { @@ -59,6 +67,53 @@ export default function Dashboard() { isDestructive={true} /> + {/* Volume Details Modal */} + {selectedVolEnv && ( +
+
+
+

+ + Volume Mounts +

+ +
+
+

+ Mounted volumes for {selectedVolEnv.name} +

+
+ {selectedVolEnv.mount_config.map((mount, idx) => ( +
+
+ Host + {mount.host_path} +
+
+ Dest + {mount.container_path} + + {mount.mode} + +
+
+ ))} +
+
+
+ +
+
+
+ )} +

Dashboard

@@ -78,7 +133,7 @@ export default function Dashboard() { {loading && environments.length === 0 ? (
Loading environments...
) : environments.length === 0 ? ( -
No environments found. Create one to get started.
+
No environments found.
) : ( @@ -110,6 +165,22 @@ export default function Dashboard() { {env.gpu_indices.length > 0 ? env.gpu_indices.join(', ') : "-"}
+