diff --git a/frontend/.eslintignore b/frontend/.eslintignore
new file mode 100644
index 0000000..a3a4b4a
--- /dev/null
+++ b/frontend/.eslintignore
@@ -0,0 +1,27 @@
+# Config files that require CommonJS
+jest.config.js
+jest.setup.js
+
+# E2E mock backend (Node.js CommonJS server)
+e2e/mock-backend.js
+
+# Test utilities
+show-interactive-direct.js
+
+# Build output
+.next/
+out/
+dist/
+build/
+
+# Dependencies
+node_modules/
+
+# Coverage
+coverage/
+.nyc_output/
+
+# Playwright
+test-results/
+playwright-report/
+playwright/.cache/
diff --git a/frontend/app/layout.tsx b/frontend/app/layout.tsx
index fa32ce1..58703a6 100644
--- a/frontend/app/layout.tsx
+++ b/frontend/app/layout.tsx
@@ -1,9 +1,17 @@
import type { Metadata } from "next";
import Script from "next/script";
+import { JetBrains_Mono } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/lib/theme";
import { Providers } from "./providers";
+const jetbrainsMono = JetBrains_Mono({
+ weight: ['400', '500', '600', '700'],
+ subsets: ['latin'],
+ display: 'swap',
+ variable: '--font-jetbrains-mono',
+});
+
export const metadata: Metadata = {
title: "Container Shell - Docker Swarm Terminal",
description: "Docker container management terminal web UI",
@@ -15,15 +23,7 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
-
-
-
-
-
+
diff --git a/frontend/components/ContainerCard/__tests__/ContainerHeader.test.tsx b/frontend/components/ContainerCard/__tests__/ContainerHeader.test.tsx
index fc047ae..37d4fe2 100644
--- a/frontend/components/ContainerCard/__tests__/ContainerHeader.test.tsx
+++ b/frontend/components/ContainerCard/__tests__/ContainerHeader.test.tsx
@@ -28,7 +28,7 @@ describe('ContainerHeader', () => {
});
it('applies success color for running status', () => {
- const { container } = render(
+ render(
);
@@ -37,7 +37,7 @@ describe('ContainerHeader', () => {
});
it('applies default color for stopped status', () => {
- const { container } = render(
+ render(
);
@@ -46,7 +46,7 @@ describe('ContainerHeader', () => {
});
it('applies warning color for paused status', () => {
- const { container } = render(
+ render(
);
diff --git a/frontend/components/__tests__/TerminalModal.test.tsx b/frontend/components/__tests__/TerminalModal.test.tsx
index 85a5626..46111d2 100644
--- a/frontend/components/__tests__/TerminalModal.test.tsx
+++ b/frontend/components/__tests__/TerminalModal.test.tsx
@@ -265,7 +265,7 @@ describe('TerminalModal', () => {
isMobile: true,
});
- const { container } = render(
+ render(
{
+ async executeCommand(containerId: string, command: string): Promise {
const token = this.getToken();
if (!token) {
triggerAuthError();
@@ -145,7 +166,7 @@ class ApiClient {
return response.json();
}
- async startContainer(containerId: string): Promise {
+ async startContainer(containerId: string): Promise {
const token = this.getToken();
if (!token) {
triggerAuthError();
@@ -172,7 +193,7 @@ class ApiClient {
return response.json();
}
- async stopContainer(containerId: string): Promise {
+ async stopContainer(containerId: string): Promise {
const token = this.getToken();
if (!token) {
triggerAuthError();
@@ -199,7 +220,7 @@ class ApiClient {
return response.json();
}
- async restartContainer(containerId: string): Promise {
+ async restartContainer(containerId: string): Promise {
const token = this.getToken();
if (!token) {
triggerAuthError();
@@ -226,7 +247,7 @@ class ApiClient {
return response.json();
}
- async removeContainer(containerId: string): Promise {
+ async removeContainer(containerId: string): Promise {
const token = this.getToken();
if (!token) {
triggerAuthError();
diff --git a/frontend/lib/hooks/__tests__/useDashboard.test.tsx b/frontend/lib/hooks/__tests__/useDashboard.test.tsx
index ef16126..e1ba166 100644
--- a/frontend/lib/hooks/__tests__/useDashboard.test.tsx
+++ b/frontend/lib/hooks/__tests__/useDashboard.test.tsx
@@ -1,4 +1,4 @@
-import { renderHook, act, waitFor } from '@testing-library/react';
+import { renderHook, act } from '@testing-library/react';
import { useDashboard } from '../useDashboard';
import { useRouter } from 'next/navigation';
import { useAppDispatch } from '@/lib/store/hooks';
diff --git a/frontend/lib/hooks/useInteractiveTerminal.ts b/frontend/lib/hooks/useInteractiveTerminal.ts
index b8cc5ac..ac7b06a 100644
--- a/frontend/lib/hooks/useInteractiveTerminal.ts
+++ b/frontend/lib/hooks/useInteractiveTerminal.ts
@@ -4,6 +4,13 @@ import { apiClient, API_BASE_URL } from '@/lib/api';
import type { Terminal } from '@xterm/xterm';
import type { FitAddon } from '@xterm/addon-fit';
+// Type declaration for debug property
+declare global {
+ interface Window {
+ _debugTerminal?: Terminal;
+ }
+}
+
interface UseInteractiveTerminalProps {
open: boolean;
containerId: string;
@@ -15,6 +22,8 @@ interface UseInteractiveTerminalProps {
export function useInteractiveTerminal({
open,
containerId,
+ // containerName is not used but required in the interface for consistency
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
containerName,
isMobile,
onFallback,
@@ -111,7 +120,7 @@ export function useInteractiveTerminal({
// Expose terminal for debugging
if (typeof window !== 'undefined') {
- (window as any)._debugTerminal = term;
+ window._debugTerminal = term;
}
// Use polling only - WebSocket is blocked by Cloudflare/reverse proxy
diff --git a/frontend/lib/store/authSlice.ts b/frontend/lib/store/authSlice.ts
index be45cff..56e9443 100644
--- a/frontend/lib/store/authSlice.ts
+++ b/frontend/lib/store/authSlice.ts
@@ -24,7 +24,7 @@ export const initAuth = createAsyncThunk('auth/init', async () => {
await apiClient.getContainers();
const username = apiClient.getUsername();
return { isAuthenticated: true, username };
- } catch (error) {
+ } catch {
// Token is invalid, clear it
apiClient.setToken(null);
return { isAuthenticated: false, username: null };
@@ -42,7 +42,7 @@ export const login = createAsyncThunk(
return { username: response.username || username };
}
return rejectWithValue(response.message || 'Login failed');
- } catch (error) {
+ } catch {
return rejectWithValue('Login failed. Please try again.');
}
}
diff --git a/frontend/lib/utils/__tests__/terminal.test.tsx b/frontend/lib/utils/__tests__/terminal.test.tsx
index eae35cb..95256c7 100644
--- a/frontend/lib/utils/__tests__/terminal.test.tsx
+++ b/frontend/lib/utils/__tests__/terminal.test.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
import { render } from '@testing-library/react';
import { formatPrompt, highlightCommand } from '../terminal';
import { OutputLine } from '@/lib/interfaces/terminal';