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
This commit is contained in:
84
frontend/src/hooks/useJSONImport.ts
Normal file
84
frontend/src/hooks/useJSONImport.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
import { useState } from 'react';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import {
|
||||
uploadJSONExport,
|
||||
commitJSONImport,
|
||||
cancelJSONImport,
|
||||
JSONImportPreview,
|
||||
JSONImportCommitResult,
|
||||
} from '../api/jsonImport';
|
||||
|
||||
/**
|
||||
* Hook for managing JSON import workflow.
|
||||
* Provides upload, commit, and cancel functionality with state management.
|
||||
*/
|
||||
export function useJSONImport() {
|
||||
const queryClient = useQueryClient();
|
||||
const [preview, setPreview] = useState<JSONImportPreview | null>(null);
|
||||
const [sessionId, setSessionId] = useState<string | null>(null);
|
||||
const [commitResult, setCommitResult] = useState<JSONImportCommitResult | null>(null);
|
||||
|
||||
const uploadMutation = useMutation({
|
||||
mutationFn: uploadJSONExport,
|
||||
onSuccess: (data) => {
|
||||
setPreview(data);
|
||||
setSessionId(data.session.id);
|
||||
},
|
||||
});
|
||||
|
||||
const commitMutation = useMutation({
|
||||
mutationFn: ({
|
||||
resolutions,
|
||||
names,
|
||||
}: {
|
||||
resolutions: Record<string, string>;
|
||||
names: Record<string, string>;
|
||||
}) => {
|
||||
if (!sessionId) throw new Error('No active session');
|
||||
return commitJSONImport(sessionId, resolutions, names);
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setCommitResult(data);
|
||||
setPreview(null);
|
||||
setSessionId(null);
|
||||
queryClient.invalidateQueries({ queryKey: ['proxy-hosts'] });
|
||||
},
|
||||
});
|
||||
|
||||
const cancelMutation = useMutation({
|
||||
mutationFn: cancelJSONImport,
|
||||
onSuccess: () => {
|
||||
setPreview(null);
|
||||
setSessionId(null);
|
||||
},
|
||||
});
|
||||
|
||||
const clearCommitResult = () => {
|
||||
setCommitResult(null);
|
||||
};
|
||||
|
||||
const reset = () => {
|
||||
setPreview(null);
|
||||
setSessionId(null);
|
||||
setCommitResult(null);
|
||||
};
|
||||
|
||||
return {
|
||||
preview,
|
||||
sessionId,
|
||||
loading: uploadMutation.isPending,
|
||||
error: uploadMutation.error,
|
||||
upload: uploadMutation.mutateAsync,
|
||||
commit: (resolutions: Record<string, string>, names: Record<string, string>) =>
|
||||
commitMutation.mutateAsync({ resolutions, names }),
|
||||
committing: commitMutation.isPending,
|
||||
commitError: commitMutation.error,
|
||||
commitResult,
|
||||
clearCommitResult,
|
||||
cancel: cancelMutation.mutateAsync,
|
||||
cancelling: cancelMutation.isPending,
|
||||
reset,
|
||||
};
|
||||
}
|
||||
|
||||
export type { JSONImportPreview, JSONImportCommitResult };
|
||||
Reference in New Issue
Block a user