Skip to content

Commit 4d96fa9

Browse files
committed
chore: mobile and performance improvements for demo
Squashed commit of the following: commit 9d2760121402497e0a4fd356725b3fcbfad68193 Author: Wojtek Majewski <wojciech.majewski@pm.me> Date: Sun May 4 18:56:03 2025 +0200 chore: update dependency versions and remove redundant entries - Removed duplicate and outdated std/internal and std/assert entries from lock file - Updated @types/node to version 18.19.87 for consistency - Added undici-types@5.26.5 with integrity hash for improved type support - Ensured dependencies are aligned and cleaned up lock file for better reproducibility commit 13ffeb6b8c1af0141eb82a14c1d0b0fac0dfbdfa Author: Wojtek Majewski <wojciech.majewski@pm.me> Date: Sun May 4 18:55:58 2025 +0200 fix: set maxPollSeconds to 2 in analyze website worker scripts - Updated analyze_website_worker_0/index.ts to include maxPollSeconds option - Updated analyze_website_worker_1/index.ts similarly - Ensures consistent polling timeout configuration across worker scripts commit 925f69b Author: Wojtek Majewski <wojciech.majewski@pm.me> Date: Sun May 4 18:55:04 2025 +0200 refactor: enhance user experience with transition states and component updates - Replace direct state updates with useTransition for smoother UI during async operations - Update website analysis flow to prevent multiple triggers and improve error handling - Refactor example links component to handle login state and start analysis asynchronously - Add disabled states and pending texts to buttons and inputs for better UX - Switch from using exampleLinks array to ExampleLinks component for modularity - Minor code cleanup and consistency improvements across components commit b78a02e Author: Wojtek Majewski <wojciech.majewski@pm.me> Date: Sun May 4 18:46:05 2025 +0200 refactor: adjust layout and styling of analysis UI panels for better responsiveness - Reordered and resized the analysis and main panels for improved mobile and desktop layout - Updated class names to enhance positioning, spacing, and visual consistency - Removed redundant code and streamlined component structure for clarity commit f62bb32 Author: Wojtek Majewski <wojciech.majewski@pm.me> Date: Sun May 4 18:40:50 2025 +0200 refactor: update layout and comments for run page UI sections Rearranged panel order for mobile and desktop views, added descriptive comments for UI components, and adjusted positioning classes for better responsiveness and clarity.
1 parent 61acf60 commit 4d96fa9

File tree

8 files changed

+179
-96
lines changed

8 files changed

+179
-96
lines changed

examples/playground/app/page.tsx

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import Hero from '@/components/hero';
22
import WebsiteAnalyzerForm from '@/components/website-analyzer-form';
33
import AuthRedirectHandler from '@/components/auth-redirect-handler';
44
import { createClient } from '@/utils/supabase/server';
5-
import { exampleLinks } from '@/lib/example-links';
5+
import ExampleLinks from '@/components/example-links';
66

77
export default async function Home() {
88
const supabase = await createClient();
@@ -35,21 +35,7 @@ export default async function Home() {
3535
<h3 className="text-lg font-medium mb-2">
3636
Example Websites to Analyze
3737
</h3>
38-
<div className="flex flex-wrap gap-4">
39-
{exampleLinks.map((link) => (
40-
<a
41-
key={link.url}
42-
href={`/websites?url=${link.url}`}
43-
className={`inline-flex px-3 py-2 ${
44-
link.variant === 'success'
45-
? 'bg-green-100 text-green-800 hover:bg-green-200'
46-
: 'bg-red-100 text-red-800 hover:bg-red-200'
47-
} rounded-md text-sm font-medium`}
48-
>
49-
{link.label}
50-
</a>
51-
))}
52-
</div>
38+
<ExampleLinks isLoggedIn={isLoggedIn} />
5339
</div>
5440
</div>
5541
</div>

examples/playground/app/websites/page.tsx

Lines changed: 45 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
'use client';
22

33
import { createClient } from '@/utils/supabase/client';
4-
import { useEffect, useState } from 'react';
4+
import { useEffect, useState, useTransition } from 'react';
55
import type { Database } from '@/supabase/functions/database-types';
66
import { Label } from '@/components/ui/label';
77
import { Input } from '@/components/ui/input';
8-
import { FormMessage, Message } from '@/components/form-message';
8+
import { FormMessage } from '@/components/form-message';
99
import { SubmitButton } from '@/components/submit-button';
1010
import { useRouter } from 'next/navigation';
1111

@@ -15,6 +15,7 @@ export default function Page() {
1515
const [websites, setWebsites] = useState<WebsiteRow[] | null>(null);
1616
const [formError, setFormError] = useState<string | null>(null);
1717
const [url, setUrl] = useState('https://reddit.com/r/supabase');
18+
const [isPending, startTransition] = useTransition();
1819
const supabase = createClient();
1920
const router = useRouter();
2021

@@ -34,32 +35,38 @@ export default function Page() {
3435
if (urlParam) {
3536
setUrl(urlParam);
3637
console.log("Found URL parameter, starting analysis:", urlParam);
37-
startAnalysis(urlParam);
38+
39+
// Use a tiny delay to ensure we're already in the client-side
40+
// This helps prevent the page from fully rendering before redirecting
41+
setTimeout(() => {
42+
startAnalysis(urlParam);
43+
}, 10);
3844
}
3945
}
4046
}, []);
4147

4248
async function startAnalysis(url: string) {
43-
if (!url) {
44-
setFormError('Please enter a URL');
49+
if (!url || isPending) {
4550
return;
4651
}
4752

4853
try {
49-
const { data, error } = await supabase.rpc('start_analyze_website_flow', {
50-
url,
51-
});
54+
startTransition(async () => {
55+
const { data, error } = await supabase.rpc('start_analyze_website_flow', {
56+
url,
57+
});
5258

53-
if (error) {
54-
setFormError(error.message);
55-
return;
56-
}
59+
if (error) {
60+
setFormError(error.message);
61+
return;
62+
}
5763

58-
if (data && data.run_id) {
59-
router.push(`/websites/runs/${data.run_id}`);
60-
} else {
61-
setFormError('Failed to start flow analysis');
62-
}
64+
if (data && data.run_id) {
65+
router.push(`/websites/runs/${data.run_id}`);
66+
} else {
67+
setFormError('Failed to start flow analysis');
68+
}
69+
});
6370
} catch (error) {
6471
setFormError('An error occurred while starting the analysis');
6572
console.error(error);
@@ -69,26 +76,28 @@ export default function Page() {
6976
async function startAnalyzeWebsiteFlow(formData: FormData) {
7077
const url = formData.get('url') as string;
7178

72-
if (!url) {
79+
if (!url || isPending) {
7380
setFormError('Please enter a URL');
7481
return;
7582
}
7683

7784
try {
78-
const { data, error } = await supabase.rpc('start_analyze_website_flow', {
79-
url,
80-
});
85+
startTransition(async () => {
86+
const { data, error } = await supabase.rpc('start_analyze_website_flow', {
87+
url,
88+
});
8189

82-
if (error) {
83-
setFormError(error.message);
84-
return;
85-
}
90+
if (error) {
91+
setFormError(error.message);
92+
return;
93+
}
8694

87-
if (data && data.run_id) {
88-
router.push(`/websites/runs/${data.run_id}`);
89-
} else {
90-
setFormError('Failed to start flow analysis');
91-
}
95+
if (data && data.run_id) {
96+
router.push(`/websites/runs/${data.run_id}`);
97+
} else {
98+
setFormError('Failed to start flow analysis');
99+
}
100+
});
92101
} catch (error) {
93102
setFormError('An error occurred while starting the analysis');
94103
console.error(error);
@@ -114,9 +123,14 @@ export default function Page() {
114123
value={url}
115124
onChange={(e) => setUrl(e.target.value)}
116125
required
126+
disabled={isPending}
117127
/>
118128
</div>
119-
<SubmitButton formAction={startAnalyzeWebsiteFlow}>
129+
<SubmitButton
130+
formAction={startAnalyzeWebsiteFlow}
131+
disabled={isPending}
132+
pendingText="🔄 Starting analysis..."
133+
>
120134
Start Analysis
121135
</SubmitButton>
122136
{formError && <FormMessage message={{ error: formError }} />}

examples/playground/app/websites/runs/[run_id]/page.tsx

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,22 +29,10 @@ function RunPageContent() {
2929

3030
return (
3131
<div className="flex flex-col lg:flex-row">
32-
{/* Main panel: User-friendly UI */}
33-
<div className="lg:w-[65%] xl:w-[70%] lg:pr-6">
34-
<WebsiteAnalysisUI
35-
runData={runData}
36-
loading={loading}
37-
error={error}
38-
onAnalyzeWebsite={analyzeWebsite}
39-
analyzeLoading={analyzeLoading}
40-
analyzeError={analyzeError}
41-
/>
42-
</div>
43-
44-
{/* Side panel: Technical details - fixed position */}
45-
<div className="lg:w-[35%] xl:w-[30%]">
32+
{/* Debug panel: Technical details - first on mobile, right side on desktop */}
33+
<div className="w-full lg:w-[35%] xl:w-[30%] order-first lg:order-last mb-6 lg:mb-0">
4634
<div
47-
className={`fixed top-16 bottom-4 right-4 lg:w-[calc(35%-2rem)] xl:w-[calc(30%-2rem)] overflow-hidden flex flex-col transition-all duration-300 group border hover:shadow-lg
35+
className={`relative lg:fixed lg:top-16 lg:bottom-4 lg:right-4 w-full lg:w-[calc(35%-2rem)] xl:w-[calc(30%-2rem)] overflow-hidden flex flex-col transition-all duration-300 group border hover:shadow-lg
4836
${isPinned
4937
? "opacity-100 border-solid border-foreground/30"
5038
: "opacity-50 hover:opacity-100 cursor-pointer border-dashed border-foreground/20 hover:border-solid"
@@ -148,6 +136,18 @@ function RunPageContent() {
148136
/>
149137
</div>
150138
</div>
139+
140+
{/* Main panel: User-friendly UI - second on mobile, left side on desktop */}
141+
<div className="w-full lg:w-[65%] xl:w-[70%] lg:pr-6 order-last lg:order-first">
142+
<WebsiteAnalysisUI
143+
runData={runData}
144+
loading={loading}
145+
error={error}
146+
onAnalyzeWebsite={analyzeWebsite}
147+
analyzeLoading={analyzeLoading}
148+
analyzeError={analyzeError}
149+
/>
150+
</div>
151151
</div>
152152
);
153153
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
'use client';
2+
3+
import { useRouter } from 'next/navigation';
4+
import { useTransition } from 'react';
5+
import { createClient } from '@/utils/supabase/client';
6+
import { exampleLinks } from '@/lib/example-links';
7+
8+
export default function ExampleLinks({ isLoggedIn }: { isLoggedIn: boolean }) {
9+
const [isPending, startTransition] = useTransition();
10+
const router = useRouter();
11+
const supabase = createClient();
12+
13+
// Function to handle example link clicks
14+
const handleExampleClick = (e: React.MouseEvent<HTMLAnchorElement>, url: string) => {
15+
if (isPending) {
16+
e.preventDefault();
17+
return;
18+
}
19+
20+
e.preventDefault();
21+
22+
// If user is not logged in, redirect to sign-in page
23+
if (!isLoggedIn) {
24+
console.log('User not logged in, storing URL and redirecting to sign-in:', url);
25+
localStorage.setItem('pendingAnalysisUrl', url);
26+
router.push('/sign-in');
27+
return;
28+
}
29+
30+
console.log('Starting analysis for example URL:', url);
31+
32+
startTransition(async () => {
33+
try {
34+
const { data, error } = await supabase.rpc('start_analyze_website_flow', {
35+
url,
36+
});
37+
38+
if (error) {
39+
console.error('Error starting analysis:', error);
40+
return;
41+
}
42+
43+
if (data && data.run_id) {
44+
console.log(
45+
'Analysis started, redirecting to:',
46+
`/websites/runs/${data.run_id}`,
47+
);
48+
router.push(`/websites/runs/${data.run_id}`);
49+
} else {
50+
console.error('No run_id returned from analysis');
51+
}
52+
} catch (error) {
53+
console.error('Exception during analysis:', error);
54+
}
55+
});
56+
};
57+
58+
return (
59+
<div className="flex flex-wrap gap-4">
60+
{exampleLinks.map((link) => (
61+
<a
62+
key={link.url}
63+
onClick={(e) => handleExampleClick(e, link.url)}
64+
href="#"
65+
className={`inline-flex px-3 py-2 ${
66+
link.variant === 'success'
67+
? 'bg-green-100 text-green-800 hover:bg-green-200'
68+
: 'bg-red-100 text-red-800 hover:bg-red-200'
69+
} rounded-md text-sm font-medium ${
70+
isPending ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'
71+
}`}
72+
aria-disabled={isPending}
73+
>
74+
{link.label}
75+
</a>
76+
))}
77+
</div>
78+
);
79+
}

examples/playground/components/website-analyzer-form.tsx

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client';
22

33
import { useRouter } from 'next/navigation';
4-
import { useState } from 'react';
4+
import { useState, useTransition } from 'react';
55
import { Label } from '@/components/ui/label';
66
import { Input } from '@/components/ui/input';
77
import { FormMessage } from '@/components/form-message';
@@ -14,6 +14,7 @@ export default function WebsiteAnalyzerForm({
1414
isLoggedIn: boolean;
1515
}) {
1616
const [formError, setFormError] = useState<string | null>(null);
17+
const [isPending, startTransition] = useTransition();
1718
const router = useRouter();
1819
const supabase = createClient();
1920

@@ -44,26 +45,29 @@ export default function WebsiteAnalyzerForm({
4445

4546
try {
4647
console.log('Starting analysis for URL:', url);
47-
const { data, error } = await supabase.rpc('start_analyze_website_flow', {
48-
url,
49-
});
48+
// Start the transition to show loading state
49+
startTransition(async () => {
50+
const { data, error } = await supabase.rpc('start_analyze_website_flow', {
51+
url,
52+
});
5053

51-
if (error) {
52-
console.error('Error starting analysis:', error);
53-
setFormError(error.message);
54-
return;
55-
}
54+
if (error) {
55+
console.error('Error starting analysis:', error);
56+
setFormError(error.message);
57+
return;
58+
}
5659

57-
if (data && data.run_id) {
58-
console.log(
59-
'Analysis started, redirecting to:',
60-
`/websites/runs/${data.run_id}`,
61-
);
62-
router.push(`/websites/runs/${data.run_id}`);
63-
} else {
64-
console.error('No run_id returned from analysis');
65-
setFormError('Failed to start flow analysis');
66-
}
60+
if (data && data.run_id) {
61+
console.log(
62+
'Analysis started, redirecting to:',
63+
`/websites/runs/${data.run_id}`,
64+
);
65+
router.push(`/websites/runs/${data.run_id}`);
66+
} else {
67+
console.error('No run_id returned from analysis');
68+
setFormError('Failed to start flow analysis');
69+
}
70+
});
6771
} catch (error) {
6872
setFormError('An error occurred while starting the analysis');
6973
console.error('Exception during analysis:', error);
@@ -87,9 +91,10 @@ export default function WebsiteAnalyzerForm({
8791
placeholder="https://example.com"
8892
defaultValue="https://example.com"
8993
required
94+
disabled={isPending}
9095
/>
9196
</div>
92-
<SubmitButton>
97+
<SubmitButton disabled={isPending} pendingText="🔄 Starting analysis...">
9398
{isLoggedIn ? '🚀 Start Analysis' : 'Sign in & Analyze'}
9499
</SubmitButton>
95100
{formError && <FormMessage message={{ error: formError }} />}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { EdgeWorker } from '@pgflow/edge-worker';
22
import AnalyzeWebsite from '../_flows/analyze_website.ts';
33

4-
EdgeWorker.start(AnalyzeWebsite);
4+
EdgeWorker.start(AnalyzeWebsite, { maxPollSeconds: 2 });
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { EdgeWorker } from '@pgflow/edge-worker';
22
import AnalyzeWebsite from '../_flows/analyze_website.ts';
33

4-
EdgeWorker.start(AnalyzeWebsite);
4+
EdgeWorker.start(AnalyzeWebsite, { maxPollSeconds: 2 });

0 commit comments

Comments
 (0)