fix: resolve TypeScript compilation errors in Docker build

- Add vitest globals type definitions to tsconfig.app.json
- Enable globals in vite.config.ts test configuration
- Add explicit vitest imports and type references to all .test.ts files
- Add missing `placeholder` property to PasswordFieldProps interface
- Add missing `required` field to test field definitions in FieldRenderer.test.tsx
- Update FieldDef and BackendMeta interfaces to support readonly arrays
- Fix readonly array type incompatibilities in BackendSelectionStep.tsx
- Fix form submission handler type mismatch in RemoteConfigStep.tsx
- Remove unused helper functions and imports from StepIndicator.test.tsx

These changes resolve all TypeScript compilation errors preventing the Docker build from completing.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-08-26 17:34:47 +02:00
co-authored by Claude Haiku 4.5
parent 2f14d217b1
commit c04b149756
12 changed files with 21 additions and 63 deletions
+2
View File
@@ -17,6 +17,7 @@ const textFieldWithTooltip = {
key: 'bucket_name', key: 'bucket_name',
label: 'Bucket Name', label: 'Bucket Name',
inputType: 'text' as const, inputType: 'text' as const,
required: true,
tooltipText: 'The name of your storage bucket', tooltipText: 'The name of your storage bucket',
}; };
@@ -24,6 +25,7 @@ const selectFieldWithTooltip = {
key: 'region', key: 'region',
label: 'Region', label: 'Region',
inputType: 'select' as const, inputType: 'select' as const,
required: true,
tooltipText: 'Select your deployment region', tooltipText: 'Select your deployment region',
options: [ options: [
{ value: 'us-east', label: 'US East' }, { value: 'us-east', label: 'US East' },
+3 -1
View File
@@ -7,11 +7,12 @@ interface PasswordFieldProps {
label: string; label: string;
error?: FieldError; error?: FieldError;
registration: UseFormRegisterReturn; registration: UseFormRegisterReturn;
placeholder?: string;
helpText?: string; helpText?: string;
tooltipText?: string; tooltipText?: string;
} }
export function PasswordField({ id, label, error, registration, helpText, tooltipText }: PasswordFieldProps) { export function PasswordField({ id, label, error, registration, placeholder, helpText, tooltipText }: PasswordFieldProps) {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [showTooltip, setShowTooltip] = useState(false); const [showTooltip, setShowTooltip] = useState(false);
const [hoverTooltip, setHoverTooltip] = useState(false); const [hoverTooltip, setHoverTooltip] = useState(false);
@@ -49,6 +50,7 @@ export function PasswordField({ id, label, error, registration, helpText, toolti
label={label} label={label}
error={error} error={error}
registration={registration} registration={registration}
placeholder={placeholder}
type={show ? 'text' : 'password'} type={show ? 'text' : 'password'}
helpText={helpText} helpText={helpText}
helpTextPrefix={tooltipIcon} helpTextPrefix={tooltipIcon}
@@ -32,7 +32,7 @@ const CATEGORY_LABELS: Record<BackendCategory, string> = {
}; };
function matchesSearch( function matchesSearch(
entry: { displayName: string; description: string; category: BackendCategory; fields: { label: string }[] }, entry: { displayName: string; description: string; category: BackendCategory; fields: readonly { label: string }[] },
query: string query: string
): boolean { ): boolean {
const q = query.toLowerCase(); const q = query.toLowerCase();
+2 -2
View File
@@ -210,8 +210,8 @@ export function RemoteConfigStep() {
return null; return null;
} }
const onNext = (values: Record<string, string>) => { const onNext = (values: Record<string, unknown>) => {
dispatch({ type: 'SET_REMOTE_PARAMS', payload: values }); dispatch({ type: 'SET_REMOTE_PARAMS', payload: values as Record<string, string> });
dispatch({ type: 'SET_STEP', payload: 2 }); dispatch({ type: 'SET_STEP', payload: 2 });
}; };
+1 -57
View File
@@ -1,6 +1,6 @@
// @vitest-environment jsdom // @vitest-environment jsdom
// Covers WIZD-03: going back preserves remote.params; deployment options are untouched // Covers WIZD-03: going back preserves remote.params; deployment options are untouched
import { describe, it, expect, vi } from 'vitest'; import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react'; import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event'; import userEvent from '@testing-library/user-event';
import React from 'react'; import React from 'react';
@@ -8,62 +8,6 @@ import { StepIndicator } from './StepIndicator';
import { WizardProvider } from '../../store/context'; import { WizardProvider } from '../../store/context';
import { useWizard } from '../../store/context'; import { useWizard } from '../../store/context';
// Helper: renders StepIndicator with a given currentStep by navigating the wizard state
function renderWithStep(currentStep: number) {
// We need a wrapper that sets the step before rendering StepIndicator
function Wrapper() {
const { dispatch } = useWizard();
React.useEffect(() => {
if (currentStep > 0) {
dispatch({ type: 'SET_STEP', payload: currentStep });
}
}, [dispatch]);
return <StepIndicator />;
}
return render(
<WizardProvider>
<Wrapper />
</WizardProvider>
);
}
// Helper: renders StepIndicator with a spy dispatch
function renderWithDispatchSpy(currentStep: number) {
const dispatched: { type: string; payload?: unknown }[] = [];
function SpyWrapper() {
const { dispatch, state } = useWizard();
React.useEffect(() => {
if (currentStep > 0) {
dispatch({ type: 'SET_STEP', payload: currentStep });
}
}, [dispatch]);
// Wrap dispatch to spy on calls after initial setup
const spyDispatch = React.useCallback(
(action: { type: string; payload?: unknown }) => {
dispatched.push(action);
dispatch(action as Parameters<typeof dispatch>[0]);
},
[dispatch]
);
return (
<div>
<span data-testid="current-step">{state.currentStep}</span>
<StepIndicatorWithDispatch dispatch={spyDispatch} />
</div>
);
}
// We'll test dispatch behavior by checking actual state changes instead
return { dispatched, ...render(<WizardProvider><SpyWrapper /></WizardProvider>) };
}
// A version of StepIndicator that accepts an optional dispatch override for testing
// Actually we'll just test via rendered output and state changes
describe('StepIndicator', () => { describe('StepIndicator', () => {
describe('WIZD-03: back navigation preserves state', () => { describe('WIZD-03: back navigation preserves state', () => {
it('step 0 shows as active when currentStep is 0', async () => { it('step 0 shows as active when currentStep is 0', async () => {
+2
View File
@@ -1,7 +1,9 @@
/// <reference types="vitest" />
// src/generators/intune-detection.test.ts // src/generators/intune-detection.test.ts
// Tests for buildIntuneDetection — Intune PowerShell detection script generator. // Tests for buildIntuneDetection — Intune PowerShell detection script generator.
// RED: imports will fail until Plan 02-03 creates intune-detection.ts. // RED: imports will fail until Plan 02-03 creates intune-detection.ts.
import { describe, it, expect } from 'vitest';
import { buildIntuneDetection } from './intune-detection'; import { buildIntuneDetection } from './intune-detection';
import { INITIAL_STATE } from '../store/types'; import { INITIAL_STATE } from '../store/types';
import type { WizardState } from '../store/types'; import type { WizardState } from '../store/types';
+2
View File
@@ -1,7 +1,9 @@
/// <reference types="vitest" />
// src/generators/intune-install.test.ts // src/generators/intune-install.test.ts
// Tests for buildIntuneInstall — Intune PowerShell install script generator. // Tests for buildIntuneInstall — Intune PowerShell install script generator.
// RED: imports will fail until Plan 02-02 creates intune-install.ts. // RED: imports will fail until Plan 02-02 creates intune-install.ts.
import { describe, it, expect } from 'vitest';
import { buildIntuneInstall } from './intune-install'; import { buildIntuneInstall } from './intune-install';
import { INITIAL_STATE } from '../store/types'; import { INITIAL_STATE } from '../store/types';
import type { WizardState } from '../store/types'; import type { WizardState } from '../store/types';
+2
View File
@@ -1,6 +1,8 @@
/// <reference types="vitest" />
// src/generators/rclone-conf.test.ts // src/generators/rclone-conf.test.ts
// Tests for buildRcloneConf — rclone INI config generator. // Tests for buildRcloneConf — rclone INI config generator.
import { describe, it, expect } from 'vitest';
import { buildRcloneConf, RCLONE_TYPE_MAP } from './rclone-conf'; import { buildRcloneConf, RCLONE_TYPE_MAP } from './rclone-conf';
import { BACKEND_REGISTRY, BackendType } from '../schemas/registry'; import { BACKEND_REGISTRY, BackendType } from '../schemas/registry';
import { INITIAL_STATE } from '../store/types'; import { INITIAL_STATE } from '../store/types';
+2
View File
@@ -1,7 +1,9 @@
/// <reference types="vitest" />
// src/generators/rmm-script.test.ts // src/generators/rmm-script.test.ts
// Tests for buildRmmScript — RMM (NinjaRMM / Datto etc.) PowerShell script generator. // Tests for buildRmmScript — RMM (NinjaRMM / Datto etc.) PowerShell script generator.
// RED: imports will fail until Plan 02-04 creates rmm-script.ts. // RED: imports will fail until Plan 02-04 creates rmm-script.ts.
import { describe, it, expect } from 'vitest';
import { buildRmmScript } from './rmm-script'; import { buildRmmScript } from './rmm-script';
import { INITIAL_STATE } from '../store/types'; import { INITIAL_STATE } from '../store/types';
import type { WizardState } from '../store/types'; import type { WizardState } from '../store/types';
+2 -2
View File
@@ -16,7 +16,7 @@ export interface FieldDef {
required: boolean; required: boolean;
placeholder?: string; placeholder?: string;
helpText?: string; helpText?: string;
options?: { value: string; label: string }[]; // for inputType: 'select' options?: readonly { value: string; label: string }[]; // for inputType: 'select'
validate?: { regex: RegExp; message: string }; validate?: { regex: RegExp; message: string };
tooltipText?: string; tooltipText?: string;
} }
@@ -25,7 +25,7 @@ export interface BackendMeta {
displayName: string; displayName: string;
description: string; description: string;
category: BackendCategory; category: BackendCategory;
fields: FieldDef[]; fields: readonly FieldDef[];
} }
export const BACKEND_REGISTRY = { export const BACKEND_REGISTRY = {
+1
View File
@@ -6,6 +6,7 @@
"lib": ["ES2020", "DOM", "DOM.Iterable"], "lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext", "module": "ESNext",
"skipLibCheck": true, "skipLibCheck": true,
"types": ["vitest/globals"],
/* Bundler mode */ /* Bundler mode */
"moduleResolution": "bundler", "moduleResolution": "bundler",
+1
View File
@@ -5,6 +5,7 @@ import tailwindcss from '@tailwindcss/vite';
export default defineConfig({ export default defineConfig({
plugins: [react(), tailwindcss()], plugins: [react(), tailwindcss()],
test: { test: {
globals: true,
environment: 'jsdom', environment: 'jsdom',
passWithNoTests: true, passWithNoTests: true,
}, },