Skip to content

Commit d880d86

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

19 files changed

+1006
-1105
lines changed

backend/app/routers/admin.py

Lines changed: 15 additions & 7 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,19 +1085,18 @@ 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))
1089-
1088+
# Handle single statement queries properly
10901089
if query_upper.startswith("SELECT") or query_upper.startswith("WITH"):
1091-
# For SELECT queries, fetch all results
1090+
# For SELECT queries, execute and fetch results
1091+
result = await db.execute(text(query))
10921092
rows = result.fetchall()
10931093

10941094
# Convert to list of dictionaries
10951095
if rows:
10961096
column_names = list(result.keys())
10971097
rows_data = [dict(zip(column_names, row)) for row in rows]
10981098
else:
1099-
column_names = []
1099+
column_names = list(result.keys()) if result.keys() else []
11001100
rows_data = []
11011101

11021102
execution_time = (time.time() - start_time) * 1000
@@ -1108,13 +1108,21 @@ async def execute_query(
11081108
execution_time_ms=round(execution_time, 2),
11091109
)
11101110
else:
1111-
# For non-SELECT queries, commit and return affected rows
1111+
# For non-SELECT queries (INSERT, UPDATE, DELETE, etc.)
1112+
# Handle multiple statements if needed
1113+
statements = [stmt.strip() for stmt in sqlparse.split(query) if stmt.strip()]
1114+
1115+
total_affected_rows = 0
1116+
for stmt in statements:
1117+
stmt_result = await db.execute(text(stmt))
1118+
total_affected_rows += stmt_result.rowcount
1119+
11121120
await db.commit()
11131121
execution_time = (time.time() - start_time) * 1000
11141122

11151123
return QueryResult(
11161124
success=True,
1117-
affected_rows=result.rowcount,
1125+
affected_rows=total_affected_rows,
11181126
execution_time_ms=round(execution_time, 2),
11191127
)
11201128

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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy