This commit is contained in:
Oliver Hofmann
2026-04-27 18:54:27 +02:00
commit 562f6ecd9c
23 changed files with 990 additions and 0 deletions
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Ollama Proxy Admin</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
+20
View File
@@ -0,0 +1,20 @@
{
"name": "ollama-proxy",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.7.9",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@vitejs/plugin-react": "^4.3.4",
"vite": "^6.0.5"
}
}
+85
View File
@@ -0,0 +1,85 @@
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import './styles.css';
function App() {
const [users, setUsers] = useState([]);
const [apiKeys, setApiKeys] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetchUsers();
fetchApiKeys();
setLoading(false);
}, []);
const fetchUsers = async () => {
const res = await axios.get('/api/users');
setUsers(res.data);
};
const fetchApiKeys = async () => {
const res = await axios.get('/api/api-keys');
setApiKeys(res.data);
};
if (loading) return <div>Loading...</div>;
return (
<div className="container">
<h1>Ollama Proxy Admin</h1>
<section>
<h2>Users</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Email</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{users.map(user => (
<tr key={user.id}>
<td>{user.id}</td>
<td>{user.username}</td>
<td>{user.email}</td>
<td>{user.is_active ? 'Active' : 'Inactive'}</td>
</tr>
))}
</tbody>
</table>
</section>
<section>
<h2>API Keys</h2>
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Key</th>
<th>User</th>
<th>Status</th>
</tr>
</thead>
<tbody>
{apiKeys.map(key => (
<tr key={key.id}>
<td>{key.id}</td>
<td>{key.name}</td>
<td>{key.key}</td>
<td>{key.user_id}</td>
<td>{key.is_active ? 'Active' : 'Inactive'}</td>
</tr>
))}
</tbody>
</table>
</section>
</div>
);
}
export default App;
+55
View File
@@ -0,0 +1,55 @@
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
h1 {
text-align: center;
margin-bottom: 40px;
color: #2c3e50;
}
h2 {
margin-bottom: 20px;
color: #34495e;
}
section {
background: white;
border-radius: 8px;
padding: 20px;
margin-bottom: 30px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
padding: 12px 15px;
text-align: left;
border-bottom: 1px solid #eee;
}
th {
background: #ecf0f1;
font-weight: 600;
color: #2c3e50;
}
tr:hover {
background: #f8f9fa;
}
.status-active {
color: #27ae60;
font-weight: 600;
}
.status-inactive {
color: #e74c3c;
font-weight: 600;
}
+11
View File
@@ -0,0 +1,11 @@
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
server: {
proxy: {
'/api': 'http://localhost:8000',
},
},
})