diff --git a/apps/playground-web/components/Playground/TerminalUI.tsx b/apps/playground-web/components/Playground/TerminalUI.tsx index d279b79..4982597 100644 --- a/apps/playground-web/components/Playground/TerminalUI.tsx +++ b/apps/playground-web/components/Playground/TerminalUI.tsx @@ -1,11 +1,32 @@ import { Dice1, Dice3, Dice5, Info } from 'lucide-react'; import Shell from '../Shell/Shell'; import { formatTime } from '@/shared/utils/commonUtils'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; + import Tooltip from '../Overlays/Tooltip'; -export function TerminalUI({ initialCommandsLeft = 1000 }) { - const [commandsLeft, setCommandsLeft] = useState(initialCommandsLeft); - const [cleanupTimeLeft, setCleanupTimeLeft] = useState(15 * 60); +import { fetchHealthCheck } from '@/lib/api'; + +export function TerminalUI() { + + const [commandsLeft, setCommandsLeft] = useState(null); + const [cleanupTimeLeft, setCleanupTimeLeft] = useState(null); + + useEffect(() => { + const initializeHealthCheck = async () => { + try { + const { commandsLeft, cleanupTimeLeft } = await fetchHealthCheck(); + setCommandsLeft(commandsLeft); + setCleanupTimeLeft(cleanupTimeLeft); + } catch (error) { + console.error('Error initializing health check:', error); + setCommandsLeft(1000); // Fallback value + setCleanupTimeLeft(15 * 60); // Fallback value + } + }; + + initializeHealthCheck(); + }, []); + const handleCommandExecuted = (commands: number, cleanup: number) => { setCommandsLeft(commands); if (cleanup !== -1) { @@ -78,3 +99,4 @@ function TerminalCounter({ ); } + diff --git a/apps/playground-web/lib/api.ts b/apps/playground-web/lib/api.ts index 3a6e916..9936e62 100644 --- a/apps/playground-web/lib/api.ts +++ b/apps/playground-web/lib/api.ts @@ -12,17 +12,48 @@ export const executeShellCommandOnServer = async ( try { const response = await WebService.post(cmdExecURL, cmdOptions); - // Check if the response contains data or if it's an error response - if (response?.body?.data) { - return response; - } else if (response?.body?.error) { - return response; - } else { - throw new Error('Unexpected response structure'); - } + // Type guard to check if the body is MonoResponse + if ('data' in response.body) { + const parsedResponse = response.body as MonoResponse; + return {headers: response.headers, body: parsedResponse}; // MonoResponse + } else { + throw new Error('Unexpected response structure'); + } + + + // // Check if the response contains data or if it's an error response + // if (response?.body?.data) { + // return response; + // } else if (response?.body?.error) { + // return response; + // } else { + // throw new Error('Unexpected response structure'); + // } } catch (error) { // Propagate the error from the backend exactly as it is console.error('Error executing command:', error); throw new Error(`${error}`); } }; + + +// Fetch health check data from the server +export const fetchHealthCheck = async (): Promise<{ commandsLeft: number; cleanupTimeLeft: number }> => { + const healthCheckURL = `/health`; + + try { + const response = await WebService.get(healthCheckURL); + + if (response?.headers) { + const commandsLeft = parseInt(response.headers['X-Commands-Left'] || '1000', 10); + const cleanupTimeLeft = parseInt(response.headers['X-Next-Cleanup-Time'] || `${15 * 60}`, 10); + + return { commandsLeft, cleanupTimeLeft }; + } else { + throw new Error('Unexpected response structure: missing headers'); + } + } catch (error) { + console.error('Error fetching health check data:', error); + throw new Error(`${error}`); + } +}; diff --git a/apps/playground-web/lib/healthResponse.ts b/apps/playground-web/lib/healthResponse.ts new file mode 100644 index 0000000..138ac18 --- /dev/null +++ b/apps/playground-web/lib/healthResponse.ts @@ -0,0 +1,3 @@ +export interface HealthResponse { + message: string | null; +} \ No newline at end of file diff --git a/apps/playground-web/lib/monoSchema.ts b/apps/playground-web/lib/monoSchema.ts deleted file mode 100644 index 16651e1..0000000 --- a/apps/playground-web/lib/monoSchema.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from 'zod'; - -const BodySchema = z.object({ - data: z.string(), -}); - -// Define the schema for an error response -const ErrorSchema = z.object({ - error: z.string(), -}); - -// Combine the schemas -export const MonoSchema = z.union([BodySchema, ErrorSchema]); diff --git a/apps/playground-web/lib/schemas.ts b/apps/playground-web/lib/schemas.ts new file mode 100644 index 0000000..e5f6a56 --- /dev/null +++ b/apps/playground-web/lib/schemas.ts @@ -0,0 +1,20 @@ +import { z } from 'zod'; + +// Schema for normal API responses +const BodySchema = z.object({ + data: z.string(), +}); + +// Define the schema for an error response +const ErrorSchema = z.object({ + error: z.string(), +}); + +// Schema for /health endpoint responses +export const HealthSchema = z.object({ + message: z.string(), +}); + +// Combined schema for normal responses +export const MonoSchema = z.union([BodySchema, ErrorSchema, HealthSchema]); + diff --git a/apps/playground-web/services/webServices.ts b/apps/playground-web/services/webServices.ts index 63c7461..65831da 100644 --- a/apps/playground-web/services/webServices.ts +++ b/apps/playground-web/services/webServices.ts @@ -1,6 +1,8 @@ -import { MonoSchema } from '@/lib/monoSchema'; +import { MonoSchema, } from '@/lib/schemas'; +import { z } from 'zod'; import { MonoResponse } from '@/lib/monoResponse'; +import { HealthResponse } from '@/lib//healthResponse'; let PLAYGROUND_MONO_URL = process.env.NEXT_PUBLIC_PLAYGROUND_MONO_URL; @@ -30,7 +32,7 @@ export const WebService = { headers: HeadersType, ): Promise<{ headers: { [key: string]: string }; - body: MonoResponse; + body: MonoResponse | HealthResponse; }> => { const options: RequestOptions = { method, @@ -69,6 +71,11 @@ export const WebService = { headers: headers, body: { data: parsedBody?.data?.data, error: null }, }; + } else if('message' in parsedBody.data) { + return { + headers: headers, + body: { message: parsedBody?.data?.message }, + }; } else { return { headers: headers, @@ -98,4 +105,5 @@ export const WebService = { post: (url: string, data: any, headers: HeadersType = {}) => { return WebService.request(url, 'POST', data, headers); }, + }; diff --git a/tooling/eslint-config/package.json b/tooling/eslint-config/package.json index c53bbfb..39e8164 100644 --- a/tooling/eslint-config/package.json +++ b/tooling/eslint-config/package.json @@ -8,12 +8,12 @@ "react-internal.js" ], "devDependencies": { + "@typescript-eslint/eslint-plugin": "^7.1.0", + "@typescript-eslint/parser": "^7.1.0", "@vercel/style-guide": "^5.2.0", - "eslint-config-turbo": "^2.0.0", "eslint-config-prettier": "^9.1.0", + "eslint-config-turbo": "^2.0.0", "eslint-plugin-only-warn": "^1.1.0", - "@typescript-eslint/parser": "^7.1.0", - "@typescript-eslint/eslint-plugin": "^7.1.0", "typescript": "^5.3.3" } }