Enhance authentication UI and improve chart rendering
- Updated the success and state mismatch HTML pages in openai_codex.py for a better user experience during authentication, including new styles and auto-reload functionality. - Modified ChartWithBulletsSlideLayout.tsx to disable animations for various chart components and adjusted the layout for better responsiveness.
This commit is contained in:
parent
1dc852d07b
commit
1141719da6
5 changed files with 512 additions and 289 deletions
|
|
@ -54,6 +54,7 @@ export function setupExportHandlers() {
|
|||
});
|
||||
const exportTaskProcess = spawn("node", [exportScriptPath, exportTaskPath], {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
cwd: baseDir,
|
||||
env: {
|
||||
...process.env,
|
||||
TEMP_DIRECTORY: tempDir,
|
||||
|
|
@ -66,11 +67,18 @@ export function setupExportHandlers() {
|
|||
},
|
||||
});
|
||||
|
||||
const stdoutChunks: string[] = [];
|
||||
const stderrChunks: string[] = [];
|
||||
|
||||
exportTaskProcess.stdout.on("data", (data: Buffer) => {
|
||||
console.log(`[Export] ${data.toString()}`);
|
||||
const text = data.toString();
|
||||
stdoutChunks.push(text);
|
||||
console.log(`[Export] ${text}`);
|
||||
});
|
||||
exportTaskProcess.stderr.on("data", (data: Buffer) => {
|
||||
console.error(`[Export] ${data.toString()}`);
|
||||
const text = data.toString();
|
||||
stderrChunks.push(text);
|
||||
console.error(`[Export] ${text}`);
|
||||
});
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
|
|
@ -79,7 +87,19 @@ export function setupExportHandlers() {
|
|||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`Export process exited with code ${code}`));
|
||||
const stderrText = stderrChunks.join("").trim() || "(no stderr)";
|
||||
const stdoutText = stdoutChunks.join("").trim();
|
||||
const detail =
|
||||
stderrText !== "(no stderr)"
|
||||
? stderrText
|
||||
: stdoutText
|
||||
? `stdout: ${stdoutText}`
|
||||
: "";
|
||||
reject(
|
||||
new Error(
|
||||
`Export process exited with code ${code}${detail ? `. ${detail}` : ""}`
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Binary file not shown.
|
|
@ -28,17 +28,211 @@ JWT_CLAIM_PATH = "https://api.openai.com/auth"
|
|||
|
||||
CALLBACK_PORT = 1455
|
||||
|
||||
SUCCESS_HTML = b"""<!doctype html>
|
||||
# Simple branded success page for Presenton authentication
|
||||
SUCCESS_HTML = """<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Authentication successful</title>
|
||||
<title>Presenton – Authentication successful</title>
|
||||
<style>
|
||||
:root {
|
||||
color-scheme: light dark;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text",
|
||||
"Segoe UI", sans-serif;
|
||||
background: radial-gradient(circle at top, #eef2ff 0, #0f172a 55%, #020617 100%);
|
||||
color: #e5e7eb;
|
||||
}
|
||||
.card {
|
||||
background: rgba(15, 23, 42, 0.9);
|
||||
border-radius: 18px;
|
||||
padding: 28px 32px 26px;
|
||||
box-shadow:
|
||||
0 18px 45px rgba(15, 23, 42, 0.75),
|
||||
0 0 0 1px rgba(148, 163, 184, 0.2);
|
||||
max-width: 440px;
|
||||
width: 92vw;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
margin: 4px 0 10px;
|
||||
color: #e5e7eb;
|
||||
}
|
||||
p {
|
||||
margin: 4px 0;
|
||||
font-size: 14px;
|
||||
color: #94a3b8;
|
||||
}
|
||||
.pill {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border-radius: 999px;
|
||||
padding: 4px 10px;
|
||||
background: rgba(22, 163, 74, 0.12);
|
||||
color: #bbf7d0;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.pill-dot {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 999px;
|
||||
background: #22c55e;
|
||||
box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.25);
|
||||
}
|
||||
.hint {
|
||||
margin-top: 14px;
|
||||
font-size: 12px;
|
||||
color: #64748b;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>Authentication successful. Return to your terminal / application to continue.</p>
|
||||
<main class="card">
|
||||
<div class="pill">
|
||||
<span class="pill-dot"></span>
|
||||
<span>Authentication successful</span>
|
||||
</div>
|
||||
<h1>You’re all set</h1>
|
||||
<p>You can now return to Presenton to continue.</p>
|
||||
<p class="hint">This window can be safely closed.</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>"""
|
||||
</html>""".encode("utf-8")
|
||||
|
||||
STATE_MISMATCH_HTML = """<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Presenton – Authentication issue</title>
|
||||
<style>
|
||||
:root { color-scheme: light dark; }
|
||||
* { box-sizing: border-box; }
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "SF Pro Text",
|
||||
"Segoe UI", sans-serif;
|
||||
background: radial-gradient(circle at top, #fef3c7 0, #0f172a 55%, #020617 100%);
|
||||
color: #e5e7eb;
|
||||
}
|
||||
.card {
|
||||
background: rgba(15, 23, 42, 0.94);
|
||||
border-radius: 18px;
|
||||
padding: 26px 30px 24px;
|
||||
box-shadow:
|
||||
0 18px 45px rgba(15, 23, 42, 0.78),
|
||||
0 0 0 1px rgba(248, 250, 252, 0.09);
|
||||
max-width: 440px;
|
||||
width: 92vw;
|
||||
text-align: center;
|
||||
backdrop-filter: blur(18px);
|
||||
}
|
||||
h1 {
|
||||
font-size: 18px;
|
||||
margin: 4px 0 8px;
|
||||
color: #fee2e2;
|
||||
}
|
||||
p {
|
||||
margin: 4px 0;
|
||||
font-size: 13px;
|
||||
color: #cbd5f5;
|
||||
}
|
||||
.badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
border-radius: 999px;
|
||||
padding: 4px 10px;
|
||||
background: rgba(239, 68, 68, 0.14);
|
||||
color: #fecaca;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.badge-dot {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
border-radius: 999px;
|
||||
background: #f97316;
|
||||
box-shadow: 0 0 0 4px rgba(248, 171, 85, 0.32);
|
||||
}
|
||||
button {
|
||||
margin-top: 14px;
|
||||
border-radius: 999px;
|
||||
padding: 7px 16px;
|
||||
border: 0;
|
||||
background: linear-gradient(135deg, #4f46e5, #22c55e);
|
||||
color: #f9fafb;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
box-shadow:
|
||||
0 10px 25px rgba(59, 130, 246, 0.55),
|
||||
0 0 0 1px rgba(15, 23, 42, 0.85);
|
||||
}
|
||||
button:active {
|
||||
transform: translateY(1px);
|
||||
box-shadow:
|
||||
0 4px 16px rgba(59, 130, 246, 0.55),
|
||||
0 0 0 1px rgba(15, 23, 42, 0.85);
|
||||
}
|
||||
.hint {
|
||||
margin-top: 10px;
|
||||
font-size: 11px;
|
||||
color: #9ca3af;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
// Gentle auto-reload after a short delay to recover from stale callback windows.
|
||||
setTimeout(function () {
|
||||
try {
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
}, 2500);
|
||||
function reloadNow() {
|
||||
try {
|
||||
window.location.reload();
|
||||
} catch (e) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<main class="card">
|
||||
<div class="badge">
|
||||
<span class="badge-dot"></span>
|
||||
<span>We noticed something unexpected</span>
|
||||
</div>
|
||||
<h1>Almost there</h1>
|
||||
<p>We detected a small mismatch while completing authentication.</p>
|
||||
<p>We’ll gently reload this page. If the issue persists, close this window and restart sign-in from Presenton.</p>
|
||||
<button type="button" onclick="reloadNow()">Reload this page</button>
|
||||
<p class="hint">You can also safely close this window and try again from the app.</p>
|
||||
</main>
|
||||
</body>
|
||||
</html>""".encode("utf-8")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
|
@ -159,7 +353,8 @@ class _CallbackHandler(BaseHTTPRequestHandler):
|
|||
# We've seen intermittent state mismatches in the field (likely from
|
||||
# overlapping auth attempts or stale callback servers), so we treat a
|
||||
# mismatch as a soft warning instead of a hard failure.
|
||||
if state_vals and state_vals[0] != expected_state:
|
||||
state_mismatch = bool(state_vals and state_vals[0] != expected_state)
|
||||
if state_mismatch:
|
||||
# Best-effort warning to server logs; handler intentionally continues.
|
||||
try:
|
||||
print(
|
||||
|
|
@ -172,7 +367,12 @@ class _CallbackHandler(BaseHTTPRequestHandler):
|
|||
self.send_response(200)
|
||||
self.send_header("Content-Type", "text/html; charset=utf-8")
|
||||
self.end_headers()
|
||||
self.wfile.write(SUCCESS_HTML)
|
||||
# Show a nicer success page, and a dedicated state-mismatch page that
|
||||
# gently reloads to help recover from stale callback windows.
|
||||
if state_mismatch:
|
||||
self.wfile.write(STATE_MISMATCH_HTML)
|
||||
else:
|
||||
self.wfile.write(SUCCESS_HTML)
|
||||
|
||||
self.server.captured_code = code_vals[0] # type: ignore[attr-defined]
|
||||
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ const ChartWithBulletsSlideLayout: React.FC<ChartWithBulletsSlideLayoutProps> =
|
|||
<YAxis {...axisProps} />
|
||||
{showTooltip && <Tooltip content={<CustomTooltip />} />}
|
||||
{showLegend && <Legend wrapperStyle={{ fontSize: '10px' }} />}
|
||||
<Bar dataKey={yAxis} barSize={70} radius={[8, 8, 0, 0]} >
|
||||
<Bar dataKey={yAxis} barSize={70} radius={[8, 8, 0, 0]} isAnimationActive={false} >
|
||||
{chartData.map((_, index) => (
|
||||
<Cell key={`cell-${index}`} fill={`var(--graph-${index}, ${CHART_COLORS[index % CHART_COLORS.length]})`} />
|
||||
))}
|
||||
|
|
@ -182,6 +182,7 @@ const ChartWithBulletsSlideLayout: React.FC<ChartWithBulletsSlideLayoutProps> =
|
|||
type="monotone"
|
||||
dataKey={yAxis}
|
||||
strokeWidth={3}
|
||||
isAnimationActive={false}
|
||||
dot={{ fill: `var(--graph-0, ${CHART_COLORS[0]})`, strokeWidth: 2, r: 4 }}
|
||||
>
|
||||
{chartData.map((_, index) => (
|
||||
|
|
@ -203,6 +204,7 @@ const ChartWithBulletsSlideLayout: React.FC<ChartWithBulletsSlideLayoutProps> =
|
|||
type="monotone"
|
||||
dataKey={yAxis}
|
||||
fillOpacity={0.6}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
{chartData.map((_, index) => (
|
||||
<Cell key={`cell-${index}`} fill={`var(--graph-${index}, ${CHART_COLORS[index % CHART_COLORS.length]})`} />
|
||||
|
|
@ -222,6 +224,7 @@ const ChartWithBulletsSlideLayout: React.FC<ChartWithBulletsSlideLayoutProps> =
|
|||
fill={`var(--background-text, ${color})`}
|
||||
dataKey={yAxis}
|
||||
label={renderPieLabel}
|
||||
isAnimationActive={false}
|
||||
>
|
||||
{chartData.map((_, index) => (
|
||||
<Cell key={`cell-${index}`} fill={`var(--graph-${index}, ${CHART_COLORS[index % CHART_COLORS.length]})`} />
|
||||
|
|
@ -238,7 +241,7 @@ const ChartWithBulletsSlideLayout: React.FC<ChartWithBulletsSlideLayoutProps> =
|
|||
<YAxis dataKey={yAxis} type="number" {...axisProps} />
|
||||
{showTooltip && <Tooltip content={<CustomTooltip />} />}
|
||||
{showLegend && <Legend wrapperStyle={{ fontSize: '10px' }} />}
|
||||
<Scatter dataKey="value" >
|
||||
<Scatter dataKey="value" isAnimationActive={false} >
|
||||
{chartData.map((_, index) => (
|
||||
<Cell key={`cell-${index}`} fill={`var(--graph-${index}, ${CHART_COLORS[index % CHART_COLORS.length]})`} />
|
||||
))}
|
||||
|
|
@ -294,13 +297,13 @@ const ChartWithBulletsSlideLayout: React.FC<ChartWithBulletsSlideLayoutProps> =
|
|||
</p>
|
||||
|
||||
{/* Chart Container */}
|
||||
<div className="flex-1 rounded-lg shadow-sm border border-gray-100 p-4"
|
||||
<div className="flex-1 min-h-[280px] rounded-lg shadow-sm border border-gray-100 p-4"
|
||||
style={{
|
||||
borderColor: 'var(--stroke, #F8F9FA)',
|
||||
}}
|
||||
>
|
||||
{/* <ChartContainer config={chartConfig} className="h-full w-full"> */}
|
||||
<ResponsiveContainer maxHeight={460} height='100%' className="">
|
||||
<ResponsiveContainer width="100%" height="100%" className="">
|
||||
|
||||
{renderChart()}
|
||||
</ResponsiveContainer>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue