Skip to content

Commit 47a5672

Browse files
committed
Cleanup frontend and unify typing
1 parent a42fd4c commit 47a5672

19 files changed

+861
-1101
lines changed

backend/app/routers/admin.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from fastapi import APIRouter, Depends, HTTPException, status, Response, Request
1010
from sqlalchemy import select, delete, func, text, desc, and_
1111
from sqlalchemy.ext.asyncio import AsyncSession
12+
import sqlparse
1213

1314
from ..database import get_database
1415
from ..admin_auth import (
@@ -1084,8 +1085,23 @@ async def execute_query(
10841085
admin_username = admin_session.github_username
10851086

10861087
try:
1087-
# Execute the query
1088-
result = await db.execute(text(query))
1088+
# Split statements using sqlparse and execute each separately
1089+
statements = [stmt.strip() for stmt in sqlparse.split(query) if stmt.strip()]
1090+
1091+
# Execute all statements
1092+
total_affected_rows = 0
1093+
for stmt in statements:
1094+
stmt_result = await db.execute(text(stmt))
1095+
total_affected_rows += stmt_result.rowcount
1096+
await db.commit()
1097+
1098+
# Create simple result object
1099+
class MultiStatementResult:
1100+
rowcount = total_affected_rows
1101+
def fetchall(self): return []
1102+
def keys(self): return []
1103+
1104+
result = MultiStatementResult()
10891105

10901106
if query_upper.startswith("SELECT") or query_upper.startswith("WITH"):
10911107
# For SELECT queries, fetch all results

backend/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ pytest
1111
pytest-asyncio
1212
httpx
1313
authlib>=1.2.0
14+
sqlparse

frontend/package-lock.json

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@radix-ui/react-tabs": "^1.1.3",
2323
"@radix-ui/react-toast": "^1.2.6",
2424
"@radix-ui/react-tooltip": "^1.1.8",
25+
"ace-builds": "^1.43.0",
2526
"class-variance-authority": "^0.7.1",
2627
"clsx": "^2.1.1",
2728
"date-fns": "^3.6.0",
@@ -32,6 +33,7 @@
3233
"patch-package": "^8.0.0",
3334
"prettier": "^3.5.3",
3435
"react": "^18.3.1",
36+
"react-ace": "^14.0.1",
3537
"react-dom": "^18.3.1",
3638
"recharts": "^2.15.1",
3739
"tailwind-merge": "^3.0.1",

frontend/src/app/admin/components/AdminUsersManager.tsx

Lines changed: 38 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,11 @@ import {
4040
Shield,
4141
Crown,
4242
} from 'lucide-react';
43-
44-
interface AdminUser {
45-
id: number;
46-
github_username: string;
47-
added_by: string;
48-
added_at: string;
49-
is_active: boolean;
50-
notes?: string;
51-
}
43+
import { api } from '@/lib/api';
44+
import type { AdminUserResponse, AdminUserCreate } from '@/lib/types';
5245

5346
export default function AdminUsersManager() {
54-
const [users, setUsers] = useState<AdminUser[]>([]);
47+
const [users, setUsers] = useState<AdminUserResponse[]>([]);
5548
const [loading, setLoading] = useState(true);
5649
const [dialogOpen, setDialogOpen] = useState(false);
5750
const [newUser, setNewUser] = useState({
@@ -60,25 +53,15 @@ export default function AdminUsersManager() {
6053
});
6154
const { toast } = useToast();
6255

63-
const API_BASE =
64-
process.env.NEXT_PUBLIC_API_BASE || 'http://localhost:8000/api';
6556

6657
useEffect(() => {
6758
fetchUsers();
6859
}, []);
6960

7061
const fetchUsers = async () => {
7162
try {
72-
const response = await fetch(`${API_BASE}/admin/users`, {
73-
credentials: 'include',
74-
});
75-
76-
if (response.ok) {
77-
const data = await response.json();
78-
setUsers(data);
79-
} else {
80-
throw new Error('Failed to fetch admin users');
81-
}
63+
const data = await api.getAdminUsersList();
64+
setUsers(data);
8265
} catch (error) {
8366
console.error('Error fetching admin users:', error);
8467
toast({
@@ -102,31 +85,18 @@ export default function AdminUsersManager() {
10285
}
10386

10487
try {
105-
const response = await fetch(`${API_BASE}/admin/users`, {
106-
method: 'POST',
107-
headers: {
108-
'Content-Type': 'application/json',
109-
},
110-
credentials: 'include',
111-
body: JSON.stringify({
112-
github_username: newUser.github_username.trim(),
113-
notes: newUser.notes.trim() || null,
114-
}),
88+
const createdUser = await api.createAdminUser({
89+
github_username: newUser.github_username.trim(),
90+
notes: newUser.notes.trim() || undefined,
91+
});
92+
93+
setUsers((prev) => [...prev, createdUser]);
94+
setNewUser({ github_username: '', notes: '' });
95+
setDialogOpen(false);
96+
toast({
97+
title: 'Success',
98+
description: `Admin user @${createdUser.github_username} created successfully`,
11599
});
116-
117-
if (response.ok) {
118-
const createdUser = await response.json();
119-
setUsers((prev) => [...prev, createdUser]);
120-
setNewUser({ github_username: '', notes: '' });
121-
setDialogOpen(false);
122-
toast({
123-
title: 'Success',
124-
description: `Admin user @${createdUser.github_username} created successfully`,
125-
});
126-
} else {
127-
const error = await response.json();
128-
throw new Error(error.detail || 'Failed to create admin user');
129-
}
130100
} catch (error) {
131101
console.error('Error creating admin user:', error);
132102
toast({
@@ -152,23 +122,14 @@ export default function AdminUsersManager() {
152122
}
153123

154124
try {
155-
const response = await fetch(`${API_BASE}/admin/users/${username}`, {
156-
method: 'DELETE',
157-
credentials: 'include',
125+
await api.deleteAdminUser(username);
126+
setUsers((prev) =>
127+
prev.filter((user) => user.github_username !== username)
128+
);
129+
toast({
130+
title: 'Success',
131+
description: `Admin user @${username} removed successfully`,
158132
});
159-
160-
if (response.ok) {
161-
setUsers((prev) =>
162-
prev.filter((user) => user.github_username !== username)
163-
);
164-
toast({
165-
title: 'Success',
166-
description: `Admin user @${username} removed successfully`,
167-
});
168-
} else {
169-
const error = await response.json();
170-
throw new Error(error.detail || 'Failed to remove admin user');
171-
}
172133
} catch (error) {
173134
console.error('Error removing admin user:', error);
174135
toast({
@@ -227,26 +188,24 @@ export default function AdminUsersManager() {
227188
<DialogContent>
228189
<DialogHeader>
229190
<DialogTitle>Add New Admin User</DialogTitle>
230-
<DialogDescription className="space-y-2">
231-
<p>
232-
Grant administrative access to a GitHub user. They will be
233-
able to access this admin panel and manage system settings.
234-
</p>
235-
<div className="p-3 bg-muted/50 border rounded-md">
236-
<div className="flex items-start gap-2">
237-
<Shield className="w-4 h-4 text-orange-500 mt-0.5 flex-shrink-0" />
238-
<div className="text-sm">
239-
<p className="font-medium">
240-
Administrative privileges include:
241-
</p>
242-
<p className="text-muted-foreground text-xs mt-1">
243-
Binary configurations • Environment settings • Run
244-
management • User administration
245-
</p>
191+
<DialogDescription>
192+
Grant administrative access to a GitHub user. They will be
193+
able to access this admin panel and manage system settings.
194+
</DialogDescription>
195+
<div className="p-3 bg-muted/50 border rounded-md">
196+
<div className="flex items-start gap-2">
197+
<Shield className="w-4 h-4 text-orange-500 mt-0.5 flex-shrink-0" />
198+
<div className="text-sm">
199+
<div className="font-medium">
200+
Administrative privileges include:
201+
</div>
202+
<div className="text-muted-foreground text-xs mt-1">
203+
Binary configurations • Environment settings • Run
204+
management • User administration
246205
</div>
247206
</div>
248207
</div>
249-
</DialogDescription>
208+
</div>
250209
</DialogHeader>
251210
<div className="space-y-4">
252211
<div>

0 commit comments

Comments
 (0)