Skip to content

Commit 8483048

Browse files
committed
feat: update TopNav dropdown to handle empty appIdOptions and change base path in Vite config
1 parent f90a19d commit 8483048

3 files changed

Lines changed: 22 additions & 105 deletions

File tree

src/features/TopNav.tsx

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,26 @@ const TopNav = ({ isConnected }: { isConnected: boolean }) => {
5757
>
5858
<div className="w-100 px-2 d-flex align-items-center gap-2">
5959
<Navbar.Brand>Essentials Dev Tools</Navbar.Brand>
60-
<Dropdown>
61-
<Dropdown.Toggle variant="link" id="dropdown-basic">
62-
{params.appId}
63-
<IconDarkChevronDown />
64-
</Dropdown.Toggle>
65-
<Dropdown.Menu>
66-
{appIdOptions.map((id) => (
67-
<Dropdown.Item key={id} as={NavLink} to={`/${id}/console`}>
68-
{id}
69-
</Dropdown.Item>
70-
))}
71-
</Dropdown.Menu>
72-
</Dropdown>
60+
{/* display a message indicating that there are no loaded applications if the appIdOptions array is empty, otherwise display the dropdown */}
61+
{appIdOptions.length === 0 ? (
62+
<span>No Loaded Applications</span>
63+
) : (
64+
<Dropdown>
65+
<Dropdown.Toggle variant="link" id="dropdown-basic">
66+
{/* display the currently selected appId or "Select Application" if no appId is selected */}
67+
{/* if no appIdOptions are available, display "No Loaded Applications" */}
68+
{params.appId || "Select Application"}
69+
<IconDarkChevronDown />
70+
</Dropdown.Toggle>
71+
<Dropdown.Menu>
72+
{appIdOptions.map((id) => (
73+
<Dropdown.Item key={id} as={NavLink} to={`/${id}/console`}>
74+
{id}
75+
</Dropdown.Item>
76+
))}
77+
</Dropdown.Menu>
78+
</Dropdown>
79+
)}
7380
<Nav className="me-auto">
7481
<NavLink
7582
className={

src/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ const root = ReactDOM.createRoot(
2323
root.render(
2424
<React.StrictMode>
2525
<Provider store={store}>
26-
<BrowserRouter basename='/debug'>
26+
<BrowserRouter basename='/cws/debug'>
2727
<App />
2828
</BrowserRouter>
2929
</Provider>

vite.config.ts

Lines changed: 1 addition & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2,96 +2,6 @@ import react from '@vitejs/plugin-react';
22
import { defineConfig, loadEnv } from 'vite';
33
import svgr from 'vite-plugin-svgr';
44

5-
/**
6-
* Vite-only plugin that creates a dynamic WebSocket reverse-proxy for the
7-
* debug session endpoint. Because the backend picks a random port in the
8-
* range 65435-65535 for each session, a static proxy target is not possible.
9-
*
10-
* Flow (dev only):
11-
* 1. Browser calls POST /debug/ws-register with the wss:// URL returned by
12-
* the debugSession API, telling the plugin which host:port to tunnel to.
13-
* 2. Browser dials ws://localhost:<vite-port>/debug/join (same origin, no
14-
* cert issues).
15-
* 3. This plugin intercepts the WebSocket upgrade, opens a TLS tunnel to
16-
* the registered target, and splices the two sockets together.
17-
*/
18-
// function dynamicWsProxyPlugin(): Plugin {
19-
// let registeredTarget: URL | null = null;
20-
21-
// return {
22-
// name: 'dynamic-ws-proxy',
23-
// configureServer(server) {
24-
// // ── Registration endpoint ─────────────────────────────────────────────
25-
// server.middlewares.use('/debug/ws-register', (req, res) => {
26-
// if (req.method !== 'POST') {
27-
// res.statusCode = 405;
28-
// res.end();
29-
// return;
30-
// }
31-
// let body = '';
32-
// req.on('data', (chunk: Buffer) => (body += chunk.toString()));
33-
// req.on('end', () => {
34-
// try {
35-
// const { url } = JSON.parse(body) as { url: string };
36-
// registeredTarget = new URL(url);
37-
// res.statusCode = 200;
38-
// res.setHeader('Content-Type', 'application/json');
39-
// res.end(JSON.stringify({ ok: true }));
40-
// } catch {
41-
// res.statusCode = 400;
42-
// res.end(JSON.stringify({ error: 'Invalid request body' }));
43-
// }
44-
// });
45-
// });
46-
47-
// // ── Dynamic WebSocket tunnel ──────────────────────────────────────────
48-
// server.httpServer?.prependListener(
49-
// 'upgrade',
50-
// (req: IncomingMessage, socket: any, head: Buffer) => {
51-
// if (!req.url?.startsWith('/debug/join') || !registeredTarget) return;
52-
53-
// const target = registeredTarget;
54-
// const useSecure =
55-
// target.protocol === 'wss:' || target.protocol === 'https:';
56-
// const port = target.port
57-
// ? parseInt(target.port, 10)
58-
// : useSecure ? 443 : 80;
59-
60-
// const upstream: net.Socket = useSecure
61-
// ? tls.connect({ host: target.hostname, port, rejectUnauthorized: false })
62-
// : net.createConnection({ host: target.hostname, port });
63-
64-
// upstream.once(useSecure ? 'secureConnect' : 'connect', () => {
65-
// // Re-emit the full HTTP Upgrade request to the upstream server
66-
// const headerLines = [
67-
// `GET ${req.url} HTTP/1.1`,
68-
// `Host: ${target.host}`,
69-
// ...Object.entries(req.headers)
70-
// .filter(([k]) => k !== 'host')
71-
// .map(([k, v]) => `${k}: ${Array.isArray(v) ? v.join(', ') : (v ?? '')}` ),
72-
// '',
73-
// '',
74-
// ];
75-
// upstream.write(headerLines.join('\r\n'));
76-
// if (head?.length) upstream.write(head);
77-
78-
// socket.pipe(upstream);
79-
// upstream.pipe(socket);
80-
// });
81-
82-
// upstream.on('error', (err: Error) => {
83-
// console.error('[dynamic-ws-proxy] upstream error:', err.message);
84-
// socket.destroy();
85-
// });
86-
// socket.on('error', () => upstream.destroy());
87-
// socket.on('close', () => upstream.destroy());
88-
// upstream.on('close', () => socket.destroy());
89-
// },
90-
// );
91-
// },
92-
// };
93-
// }
94-
955
export default defineConfig(({ mode }) => {
966
const env = loadEnv(mode, process.cwd(), '');
977

@@ -101,7 +11,7 @@ export default defineConfig(({ mode }) => {
10111
}
10212

10313
return {
104-
base: '/debug/',
14+
base: '/cws/debug/',
10515
plugins: [react(), svgr({ include: '**/*.svg', svgrOptions: { exportType: 'named' } })],
10616
server: {
10717
proxy: programHost

0 commit comments

Comments
 (0)