diff --git a/ui/components/SessionsPage.tsx b/ui/components/SessionsPage.tsx index 04b67fc..cb2ddee 100644 --- a/ui/components/SessionsPage.tsx +++ b/ui/components/SessionsPage.tsx @@ -1007,7 +1007,7 @@ export const SessionsPage = ({ const eventId = e.currentTarget.getAttribute('data-event-id'); e.currentTarget.disabled = true; try { - const res = await fetch(\`/api/events/\${eventId}/extend\`, { + const res = await fetch('/api/events/' + eventId + '/extend', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ extendHours: 1 }) @@ -1036,7 +1036,7 @@ export const SessionsPage = ({ e.currentTarget.textContent = 'Revoking...'; try { - const res = await fetch(\`/api/events/\${eventId}/end\`, { + const res = await fetch('/api/events/' + eventId + '/end', { method: 'POST', }); if (res.ok) { @@ -1047,6 +1047,7 @@ export const SessionsPage = ({ showNotice(data.error || 'Failed to end event', true); e.currentTarget.disabled = false; e.currentTarget.textContent = '🔴 End & Revoke All'; + } } catch (err) { showNotice('Network error ending event', true); e.currentTarget.disabled = false; @@ -1066,7 +1067,7 @@ export const SessionsPage = ({ e.currentTarget.disabled = true; try { - const res = await fetch(\`/api/sessions/\${sessionId}\`, { + const res = await fetch('/api/sessions/' + sessionId, { method: 'DELETE' }); diff --git a/ui/ui_scripts.test.ts b/ui/ui_scripts.test.ts new file mode 100644 index 0000000..e437ffb --- /dev/null +++ b/ui/ui_scripts.test.ts @@ -0,0 +1,135 @@ +import { assertEquals } from "jsr:@std/assert@1"; +import { SessionsPage } from "./components/SessionsPage.tsx"; +import { LoginPage } from "./components/LoginPage.tsx"; +import { RegisterPage } from "./components/RegisterPage.tsx"; +import { EventJoinPage } from "./components/EventJoinPage.tsx"; +import { EventSplashPage } from "./components/EventSplashPage.tsx"; +import { PasskeysPage } from "./components/PasskeysPage.tsx"; +import { AdminAppsPage } from "./components/AdminAppsPage.tsx"; +import { AdminInvitesPage } from "./components/AdminInvitesPage.tsx"; +import { AdminRolesPage } from "./components/AdminRolesPage.tsx"; +import { AdminUsersPage } from "./components/AdminUsersPage.tsx"; +import { AdminUserDetailsPage } from "./components/AdminUserDetailsPage.tsx"; +import { AuditLogPage } from "./components/AuditLogPage.tsx"; +import { AAGUIDPage } from "./components/AAGUIDPage.tsx"; + +function validateJsSyntax(componentName: string, jsxResult: any) { + const html = String(jsxResult); + const scriptRegex = /]*)>([\s\S]*?)<\/script>/gi; + let match; + let scriptCount = 0; + while ((match = scriptRegex.exec(html)) !== null) { + const isModule = match[1].includes('type="module"') || + match[1].includes("type='module'"); + const scriptContent = match[2].trim(); + if (!scriptContent) continue; + scriptCount++; + try { + if (isModule) { + // Strip import statements for syntax compilation check in new Function + const cleanContent = scriptContent.replace( + /import\s+[\s\S]*?from\s+['"][^'"]+['"];?/g, + "// import stripped", + ); + new Function(cleanContent); + } else { + new Function(scriptContent); + } + } catch (err: any) { + throw new Error( + `Syntax error in