Skip to content

Commit d9fc23f

Browse files
committed
Merge branch 'main' into load-canvas-backup
2 parents 80ee80c + e09b559 commit d9fc23f

File tree

10 files changed

+440
-306
lines changed

10 files changed

+440
-306
lines changed

.github/workflows/docker-build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
with:
5454
context: .
5555
push: ${{ github.event_name != 'pull_request' }}
56-
platforms: linux/amd64,linux/arm64
56+
platforms: ${{ github.ref == 'refs/heads/main' && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
5757
tags: ${{ steps.meta.outputs.tags }}
5858
labels: ${{ steps.meta.outputs.labels }}
5959
cache-from: type=gha

src/frontend/public/auth/popup-close.html

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,11 @@
33
<head>
44
<meta charset="UTF-8" />
55
<title>Authentication Complete</title>
6-
<style>
7-
body {
8-
background: #18181b;
9-
color: #fff;
10-
font-family: sans-serif;
11-
display: flex;
12-
flex-direction: column;
13-
align-items: center;
14-
justify-content: center;
15-
height: 100vh;
16-
margin: 0;
17-
}
18-
.message {
19-
margin-bottom: 2rem;
20-
font-size: 1.2rem;
21-
}
22-
</style>
236
</head>
247
<body>
25-
<div class="message">Authentication complete! You may close this window.</div>
268
<script>
279
localStorage.setItem('auth_completed', Date.now().toString());
28-
// Close the window after a short delay to ensure message is sent
29-
setTimeout(() => {
30-
window.close();
31-
}, 100);
10+
window.close()
3211
</script>
3312
</body>
3413
</html>

src/frontend/src/AuthGate.tsx

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,37 @@ export default function AuthGate({ children }: { children: React.ReactNode }) {
5050
// eslint-disable-next-line react-hooks/exhaustive-deps
5151
}, [isAuthenticated, coderAuthDone]);
5252

53+
// State to control modal visibility and exit animation
54+
const [showAuthModal, setShowAuthModal] = useState(false);
55+
const [isExiting, setIsExiting] = useState(false);
56+
57+
// Update showAuthModal when authentication status changes
58+
useEffect(() => {
59+
if (isAuthenticated === false) {
60+
setShowAuthModal(true);
61+
setIsExiting(false);
62+
} else if (isAuthenticated === true && showAuthModal) {
63+
// Start exit animation when user becomes authenticated
64+
setIsExiting(true);
65+
// Modal will be removed after animation completes via onExitComplete
66+
}
67+
}, [isAuthenticated, showAuthModal]);
68+
69+
// Handle exit animation completion
70+
const handleExitComplete = () => {
71+
setShowAuthModal(false);
72+
};
73+
5374
// Always render children; overlay AuthModal if not authenticated
5475
return (
5576
<>
5677
{children}
57-
{isAuthenticated === false && <AuthModal />}
78+
{showAuthModal && (
79+
<AuthModal
80+
isExiting={isExiting}
81+
onExitComplete={handleExitComplete}
82+
/>
83+
)}
5884
</>
5985
);
6086
}

src/frontend/src/api/apiUtils.ts

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,39 @@
1+
import { queryClient } from './queryClient';
2+
3+
/**
4+
* Handle unauthorized errors by updating the auth state in the query cache
5+
* This will trigger the AuthModal to appear
6+
*/
7+
export function handleUnauthorized() {
8+
// Set auth state to false to trigger the AuthModal
9+
queryClient.setQueryData(['auth'], false);
10+
}
11+
112
// Common error handling for API responses
213
export async function handleResponse(response: Response) {
3-
if (!response.ok) {
4-
if (response.status === 401) {
5-
throw new Error('Unauthorized');
6-
}
7-
8-
const errorText = await response.text();
9-
throw new Error(errorText || `API error: ${response.status}`);
14+
if (!response.ok) {
15+
if (response.status === 401) {
16+
// Update auth state when 401 is encountered
17+
handleUnauthorized();
18+
throw new Error('Unauthorized');
1019
}
1120

12-
// For endpoints that return no content
13-
if (response.status === 204) {
14-
return null;
15-
}
16-
17-
// For endpoints that return JSON
18-
return response.json();
21+
const errorText = await response.text();
22+
throw new Error(errorText || `API error: ${response.status}`);
1923
}
2024

21-
// Base fetch function with error handling
22-
export async function fetchApi(url: string, options?: RequestInit) {
25+
// For endpoints that return no content
26+
if (response.status === 204) {
27+
return null;
28+
}
29+
30+
// For endpoints that return JSON
31+
return response.json();
32+
}
33+
34+
// Base fetch function with error handling
35+
export async function fetchApi(url: string, options?: RequestInit) {
36+
try {
2337
const response = await fetch(url, {
2438
...options,
2539
credentials: 'include',
@@ -30,4 +44,8 @@ export async function handleResponse(response: Response) {
3044
});
3145

3246
return handleResponse(response);
33-
}
47+
} catch (error) {
48+
// Re-throw the error after handling it
49+
throw error;
50+
}
51+
}

src/frontend/src/api/hooks.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export const api = {
7070
// Map backend 'state' property to frontend 'status'
7171
return { ...result, status: result.state };
7272
} catch (error) {
73+
// Let the error propagate to be handled by the global error handler
7374
throw error;
7475
}
7576
},

src/frontend/src/api/queryClient.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export const queryClient = new QueryClient({
77
retry: 1,
88
refetchOnWindowFocus: true,
99
staleTime: 30000, // 30 seconds
10-
cacheTime: 1000 * 60 * 5, // 5 minutes
10+
gcTime: 1000 * 60 * 5, // 5 minutes (formerly cacheTime)
1111
refetchOnMount: true,
1212
},
1313
},

0 commit comments

Comments
 (0)