Files
Charon/frontend/src/api/jsonImport.ts
GitHub Actions bc15e976b2 chore: implement NPM/JSON import routes and fix SMTP persistence
Phase 3 of skipped tests remediation - enables 7 previously skipped E2E tests

Backend:

Add NPM import handler with session-based upload/commit/cancel
Add JSON import handler with Charon/NPM format support
Fix SMTP SaveSMTPConfig using transaction-based upsert
Add comprehensive unit tests for new handlers
Frontend:

Add ImportNPM page component following ImportCaddy pattern
Add ImportJSON page component with format detection
Add useNPMImport and useJSONImport React Query hooks
Add API clients for npm/json import endpoints
Register routes in App.tsx and navigation in Layout.tsx
Add i18n keys for new import pages
Tests:

7 E2E tests now enabled and passing
Backend coverage: 86.8%
Reduced total skipped tests from 98 to 91
Closes: Phase 3 of skipped-tests-remediation plan
2026-01-24 22:22:40 +00:00

91 lines
2.4 KiB
TypeScript

import client from './client';
/** Represents a host parsed from a JSON export. */
export interface JSONHost {
domain_names: string;
forward_scheme: string;
forward_host: string;
forward_port: number;
ssl_forced: boolean;
websocket_support: boolean;
}
/** Preview of a JSON import with hosts and conflicts. */
export interface JSONImportPreview {
session: {
id: string;
state: string;
source: string;
};
preview: {
hosts: JSONHost[];
conflicts: string[];
errors: string[];
};
conflict_details: Record<string, {
existing: {
forward_scheme: string;
forward_host: string;
forward_port: number;
ssl_forced: boolean;
websocket: boolean;
enabled: boolean;
};
imported: {
forward_scheme: string;
forward_host: string;
forward_port: number;
ssl_forced: boolean;
websocket: boolean;
};
}>;
}
/** Result of committing a JSON import operation. */
export interface JSONImportCommitResult {
created: number;
updated: number;
skipped: number;
errors: string[];
}
/**
* Uploads JSON export content for import preview.
* @param content - The JSON export content as a string
* @returns Promise resolving to JSONImportPreview with parsed hosts
* @throws {AxiosError} If parsing fails or content is invalid
*/
export const uploadJSONExport = async (content: string): Promise<JSONImportPreview> => {
const { data } = await client.post<JSONImportPreview>('/import/json/upload', { content });
return data;
};
/**
* Commits the JSON import, creating/updating proxy hosts.
* @param sessionUuid - The import session UUID
* @param resolutions - Map of conflict resolutions (domain -> 'keep'|'replace'|'skip')
* @param names - Map of custom names for imported hosts
* @returns Promise resolving to JSONImportCommitResult with counts
* @throws {AxiosError} If commit fails
*/
export const commitJSONImport = async (
sessionUuid: string,
resolutions: Record<string, string>,
names: Record<string, string>
): Promise<JSONImportCommitResult> => {
const { data } = await client.post<JSONImportCommitResult>('/import/json/commit', {
session_uuid: sessionUuid,
resolutions,
names,
});
return data;
};
/**
* Cancels the current JSON import session.
* @throws {AxiosError} If cancellation fails
*/
export const cancelJSONImport = async (): Promise<void> => {
await client.post('/import/json/cancel');
};