From e033b06da8d8f82288c02d6b079296a8bfe6b250 Mon Sep 17 00:00:00 2001 From: ignasmailer Date: Tue, 24 Feb 2026 16:50:34 +0100 Subject: [PATCH 1/4] fix: prevent Design tab from appearing active on non-design routes The activeNavButton memo had a catch-all fallback to 'design', causing the Design button to appear active on Settings, Localization, Profile, and Integrations pages. Now it explicitly checks for design route types and returns null for unrelated routes. Co-authored-by: Cursor --- app/ycode/components/HeaderBar.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/ycode/components/HeaderBar.tsx b/app/ycode/components/HeaderBar.tsx index 6214bb28..b9c98de9 100644 --- a/app/ycode/components/HeaderBar.tsx +++ b/app/ycode/components/HeaderBar.tsx @@ -107,11 +107,12 @@ export default function HeaderBar({ }, [routeType, optimisticNav]); // Derive active button: optimistic state takes priority, then URL - const activeNavButton = useMemo((): NavButton => { + const activeNavButton = useMemo((): NavButton | null => { if (optimisticNav) return optimisticNav; if (routeType === 'collection' || routeType === 'collections-base') return 'cms'; if (routeType === 'forms') return 'forms'; - return 'design'; + if (routeType === 'layers' || routeType === 'page' || routeType === 'component' || routeType === null) return 'design'; + return null; }, [optimisticNav, routeType]); const [theme, setTheme] = useState<'system' | 'light' | 'dark'>(() => { From 036817f9e7c95fdcb1e032069db663e6d54a9249 Mon Sep 17 00:00:00 2001 From: ignasmailer Date: Tue, 24 Feb 2026 17:53:19 +0100 Subject: [PATCH 2/4] fix: improve setup email confirmation check Query GoTrue's /settings endpoint instead of creating a throwaway test user to detect the autoconfirm flag. The previous approach broke when Supabase rejected fake email domains. Also surface the actual server error message in the client instead of a generic HTTP 500 string. Co-authored-by: Cursor --- .../api/setup/check-email-confirm/route.ts | 52 +++++ app/ycode/welcome/page.tsx | 221 ++++++++++++------ lib/api/setup.ts | 17 ++ 3 files changed, 225 insertions(+), 65 deletions(-) create mode 100644 app/ycode/api/setup/check-email-confirm/route.ts diff --git a/app/ycode/api/setup/check-email-confirm/route.ts b/app/ycode/api/setup/check-email-confirm/route.ts new file mode 100644 index 00000000..fe938d53 --- /dev/null +++ b/app/ycode/api/setup/check-email-confirm/route.ts @@ -0,0 +1,52 @@ +import { noCache } from '@/lib/api-response'; +import { getSupabaseConfig } from '@/lib/supabase-server'; + +export const dynamic = 'force-dynamic'; +export const revalidate = 0; + +/** + * GET /ycode/api/setup/check-email-confirm + * + * Checks whether the Supabase "Confirm email" setting is disabled + * by querying GoTrue's public /settings endpoint which exposes + * the mailer autoconfirm flag. + */ +export async function GET() { + try { + const creds = await getSupabaseConfig(); + + if (!creds) { + return noCache( + { error: 'Supabase not configured' }, + 500 + ); + } + + const settingsResponse = await fetch( + `${creds.projectUrl}/auth/v1/settings`, + { + headers: { 'apikey': creds.anonKey }, + } + ); + + if (!settingsResponse.ok) { + return noCache( + { error: 'Failed to fetch auth settings from Supabase' }, + 500 + ); + } + + const settings = await settingsResponse.json(); + const isAutoconfirm = settings.mailer_autoconfirm === true; + + return noCache({ + autoconfirm: isAutoconfirm, + }); + } catch (error) { + console.error('Check email confirm failed:', error); + return noCache( + { error: 'Failed to check email confirmation setting' }, + 500 + ); + } +} diff --git a/app/ycode/welcome/page.tsx b/app/ycode/welcome/page.tsx index 775db973..c3142dc1 100644 --- a/app/ycode/welcome/page.tsx +++ b/app/ycode/welcome/page.tsx @@ -15,6 +15,7 @@ import { connectSupabase, runMigrations, completeSetup, + checkEmailConfirmDisabled, } from '@/lib/api/setup'; import { Label } from '@/components/ui/label'; import { Button } from '@/components/ui/button'; @@ -75,7 +76,7 @@ function LogoBottomRight() { export default function WelcomePage() { const router = useRouter(); - const { currentStep, setStep, setSupabaseConfig, markComplete } = useSetupStore(); + const { currentStep, setStep, setSupabaseConfig, supabaseConfig, markComplete } = useSetupStore(); const { session, isLoading: isAuthLoading } = useAuthSession(); const [loading, setLoading] = useState(false); @@ -89,6 +90,16 @@ export default function WelcomePage() { const [password, setPassword] = useState(''); const [confirmPassword, setConfirmPassword] = useState(''); + // Supabase connection fields (pre-populated from store if available) + const [anonKey, setAnonKey] = useState(supabaseConfig?.anonKey || ''); + const [serviceRoleKey, setServiceRoleKey] = useState(supabaseConfig?.serviceRoleKey || ''); + const [connectionUrl, setConnectionUrl] = useState(supabaseConfig?.connectionUrl || ''); + const [dbPassword, setDbPassword] = useState(supabaseConfig?.dbPassword || ''); + + // Email confirmation setting check + const [emailConfirmDisabled, setEmailConfirmDisabled] = useState(false); + const [checkingEmailConfirm, setCheckingEmailConfirm] = useState(false); + // Ensure dark mode is applied on client-side navigation useEffect(() => { document.documentElement.classList.add('dark'); @@ -439,12 +450,11 @@ export default function WelcomePage() { setLoading(true); setError(null); - const formData = new FormData(e.currentTarget); const config: SupabaseConfig = { - anonKey: formData.get('anon_key') as string, - serviceRoleKey: formData.get('service_role_key') as string, - connectionUrl: formData.get('connection_url') as string, - dbPassword: formData.get('db_password') as string, + anonKey, + serviceRoleKey, + connectionUrl, + dbPassword, }; try { @@ -511,6 +521,8 @@ export default function WelcomePage() { setAnonKey(e.target.value)} required size="sm" /> @@ -524,6 +536,8 @@ export default function WelcomePage() { setServiceRoleKey(e.target.value)} required size="sm" /> @@ -538,6 +552,8 @@ export default function WelcomePage() { type="text" id="connection_url" name="connection_url" + value={connectionUrl} + onChange={(e) => setConnectionUrl(e.target.value)} required size="sm" /> @@ -552,6 +568,8 @@ export default function WelcomePage() { type="password" id="db_password" name="db_password" + value={dbPassword} + onChange={(e) => setDbPassword(e.target.value)} required size="sm" /> @@ -689,6 +707,31 @@ export default function WelcomePage() { // Step 4: Create Admin Account if (currentStep === 'admin') { + const handleCheckEmailConfirm = async () => { + setCheckingEmailConfirm(true); + setError(null); + + try { + const result = await checkEmailConfirmDisabled(); + + if (result.error) { + setError(result.error); + return; + } + + if (!result.autoconfirm) { + setError('Confirm email setting in Supabase is not disabled.'); + return; + } + + setEmailConfirmDisabled(true); + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to check setting'); + } finally { + setCheckingEmailConfirm(false); + } + }; + const handleComplete = async () => { setLoading(true); setError(null); @@ -769,71 +812,119 @@ export default function WelcomePage() { -
+ {!emailConfirmDisabled ? ( +
- -
- +
+
+ +

+ In your Supabase project, find and disable the setting below. +

+
+
+ Authentication + + Sign In / Providers + + Confirm email +
+

+ The confirmation email is not needed. +

+
- {error && ( - - {error} - - )} + {error && ( + + {error} + + )} - - Email - setEmail(e.target.value)} - disabled={loading} - size="sm" - /> - - - - Password - setPassword(e.target.value)} - disabled={loading} - size="sm" - /> - At least 6 characters - - - - Confirm password - setConfirmPassword(e.target.value)} - disabled={loading} - size="sm" - /> - +
+ + +
-
- - Your user will be stored securely in Supabase Auth. -
+
+ ) : ( +
+ + +
+ + + {error && ( + + {error} + + )} + + + Email + setEmail(e.target.value)} + disabled={loading} + size="sm" + /> + + + + Password + setPassword(e.target.value)} + disabled={loading} + size="sm" + /> + At least 6 characters + + + + Confirm password + setConfirmPassword(e.target.value)} + disabled={loading} + size="sm" + /> + + +
+ + Your user will be stored securely in Supabase Auth. +
-
-
-
+ + + -
+
+ )} diff --git a/lib/api/setup.ts b/lib/api/setup.ts index db0a087d..d4d75ecf 100644 --- a/lib/api/setup.ts +++ b/lib/api/setup.ts @@ -53,6 +53,23 @@ export async function runMigrations(): Promise> { return response.json(); } +/** + * Check if Supabase "Confirm email" setting is disabled (autoconfirm enabled) + */ +export async function checkEmailConfirmDisabled(): Promise<{ + autoconfirm: boolean; + error?: string; +}> { + const response = await fetch('/ycode/api/setup/check-email-confirm'); + const data = await response.json(); + + if (!response.ok) { + throw new Error(data?.error || `HTTP ${response.status}: ${response.statusText}`); + } + + return data; +} + /** * Complete setup (no-op now, kept for compatibility) */ From 0e2f3631b7ec1466ac7017b0cc69512e3034dfac Mon Sep 17 00:00:00 2001 From: Tristan Mouchet Date: Tue, 24 Feb 2026 16:37:43 +0100 Subject: [PATCH 3/4] chore: add GitHub issue & pull request templates --- .github/ISSUE_TEMPLATE/bug-report.yml | 80 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/config.yml | 8 +++ .github/ISSUE_TEMPLATE/feature-request.yml | 56 +++++++++++++++ .github/PULL_REQUEST_TEMPLATE.md | 15 ++++ 4 files changed, 159 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 00000000..07a5df69 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,80 @@ +name: Bug Report +description: Report a bug or unexpected behavior in Ycode +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report a bug! Please fill out the sections below so we can reproduce and fix the issue. + + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of the bug. + placeholder: Describe what went wrong... + validations: + required: true + + - type: textarea + id: steps + attributes: + label: Steps to reproduce + description: Detailed steps to reproduce the behavior. + placeholder: | + 1. Go to '...' + 2. Click on '...' + 3. Scroll down to '...' + 4. See error + validations: + required: true + + - type: textarea + id: expected + attributes: + label: Expected behavior + description: What you expected to happen. + validations: + required: true + + - type: textarea + id: actual + attributes: + label: Actual behavior + description: What actually happened. + validations: + required: true + + - type: textarea + id: screenshots + attributes: + label: Screenshots or screen recordings + description: If applicable, add screenshots or recordings to help explain the problem. + + - type: dropdown + id: deployment + attributes: + label: Deployment type + options: + - Self-hosted + - Ycode Cloud + validations: + required: true + + - type: input + id: browser + attributes: + label: Browser + placeholder: e.g. Chrome 120, Firefox 121, Safari 17 + + - type: input + id: os + attributes: + label: Operating system + placeholder: e.g. macOS 15, Windows 11, Ubuntu 24.04 + + - type: textarea + id: additional + attributes: + label: Additional context + description: Any other context about the problem (error messages, console logs, etc.). diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..e5ecdf57 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: Documentation + url: https://docs.ycode.com + about: Check the docs — your question may already be answered. + - name: Discord Community + url: https://discord.gg/xadfw2DV4q + about: Chat with the community and get help with self-hosting. diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 00000000..874f4497 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,56 @@ +name: Feature Request +description: Suggest a new feature or improvement for Ycode +labels: ["enhancement"] +body: + - type: markdown + attributes: + value: | + Thanks for suggesting a feature! Please describe your idea below. + + - type: textarea + id: problem + attributes: + label: Problem or motivation + description: What problem does this feature solve? Is it related to a frustration? + placeholder: I'm always frustrated when... + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed solution + description: Describe the solution you'd like. Be as specific as possible. + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Describe any alternative solutions or workarounds you've considered. + + - type: dropdown + id: area + attributes: + label: Area + description: Which part of Ycode does this relate to? + options: + - Visual Editor + - Collections / CMS + - Pages & Routing + - Components + - Assets & Media + - Design Properties + - Settings + - API + - Self-hosting / Deployment + - Other + validations: + required: true + + - type: textarea + id: additional + attributes: + label: Additional context + description: Any mockups, screenshots, or references that help illustrate the feature. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000..d97cf1dc --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,15 @@ +## Summary + + + +## Changes + + + +- + +## Test plan + + + +- [ ] From aafc2eef55cf4872ffa3fa416eaab8696d1b9e6d Mon Sep 17 00:00:00 2001 From: Liam Walder Date: Tue, 24 Feb 2026 17:49:52 +0000 Subject: [PATCH 4/4] chore: add release script to gitignore Co-authored-by: Cursor --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 40feaa06..6248938a 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ next-env.d.ts # turbo .turbo + +# scripts +release.sh