Wizard: fix imported repositories not preselected

This fixes a bug that was caused by using incorrect ids of imported
custom repositories. Due to that bug, only in some cases the
repositories were correctly preselected.
This commit is contained in:
Anna Vítová 2025-04-15 13:55:03 +02:00 committed by Klara Simickova
parent 774714cb99
commit fad33a32c8
2 changed files with 100 additions and 57 deletions

View file

@ -23,6 +23,7 @@ import { useNavigate } from 'react-router-dom';
import { mapOnPremToHosted } from './helpers/onPremToHostedBlueprintMapper'; import { mapOnPremToHosted } from './helpers/onPremToHostedBlueprintMapper';
import { import {
ApiRepositoryImportResponseRead,
ApiRepositoryRequest, ApiRepositoryRequest,
useBulkImportRepositoriesMutation, useBulkImportRepositoriesMutation,
} from '../../store/contentSourcesApi'; } from '../../store/contentSourcesApi';
@ -30,10 +31,14 @@ import { useAppDispatch } from '../../store/hooks';
import { import {
BlueprintExportResponse, BlueprintExportResponse,
BlueprintItem, BlueprintItem,
CustomRepository,
} from '../../store/imageBuilderApi'; } from '../../store/imageBuilderApi';
import { importCustomRepositories, wizardState } from '../../store/wizardSlice'; import { wizardState } from '../../store/wizardSlice';
import { resolveRelPath } from '../../Utilities/path'; import { resolveRelPath } from '../../Utilities/path';
import { mapExportRequestToState } from '../CreateImageWizard/utilities/requestMapper'; import {
mapExportRequestToState,
mapToCustomRepositories,
} from '../CreateImageWizard/utilities/requestMapper';
interface ImportBlueprintModalProps { interface ImportBlueprintModalProps {
setShowImportModal: React.Dispatch<React.SetStateAction<boolean>>; setShowImportModal: React.Dispatch<React.SetStateAction<boolean>>;
@ -73,7 +78,7 @@ export const ImportBlueprintModal: React.FunctionComponent<
async function handleRepositoryImport( async function handleRepositoryImport(
blueprintExportedResponse: BlueprintExportResponse blueprintExportedResponse: BlueprintExportResponse
) { ): Promise<CustomRepository[] | undefined> {
if (isCheckedImportRepos && blueprintExportedResponse.content_sources) { if (isCheckedImportRepos && blueprintExportedResponse.content_sources) {
const customRepositories: ApiRepositoryRequest[] = const customRepositories: ApiRepositoryRequest[] =
blueprintExportedResponse.content_sources.map( blueprintExportedResponse.content_sources.map(
@ -84,15 +89,17 @@ export const ImportBlueprintModal: React.FunctionComponent<
const result = await importRepositories({ const result = await importRepositories({
body: customRepositories, body: customRepositories,
}).unwrap(); }).unwrap();
dispatch(
importCustomRepositories(
blueprintExportedResponse.customizations.custom_repositories || []
)
);
if (Array.isArray(result)) { if (Array.isArray(result)) {
const importedRepositoryNames: string[] = []; const importedRepositoryNames: string[] = [];
const newCustomRepos: CustomRepository[] = [];
result.forEach((repository) => { result.forEach((repository) => {
const contentSourcesRepo =
repository as ApiRepositoryImportResponseRead;
if (contentSourcesRepo.uuid) {
newCustomRepos.push(
...mapToCustomRepositories(contentSourcesRepo)
);
}
if (repository.warnings?.length === 0 && repository.url) { if (repository.warnings?.length === 0 && repository.url) {
importedRepositoryNames.push(repository.url); importedRepositoryNames.push(repository.url);
return; return;
@ -105,6 +112,7 @@ export const ImportBlueprintModal: React.FunctionComponent<
}) })
); );
}); });
if (importedRepositoryNames.length !== 0) { if (importedRepositoryNames.length !== 0) {
dispatch( dispatch(
addNotification({ addNotification({
@ -114,6 +122,7 @@ export const ImportBlueprintModal: React.FunctionComponent<
}) })
); );
} }
return newCustomRepos;
} }
} catch { } catch {
dispatch( dispatch(
@ -128,62 +137,77 @@ export const ImportBlueprintModal: React.FunctionComponent<
React.useEffect(() => { React.useEffect(() => {
if (filename && fileContent) { if (filename && fileContent) {
try { const parseAndImport = async () => {
const isToml = filename.endsWith('.toml'); try {
const isJson = filename.endsWith('.json'); const isToml = filename.endsWith('.toml');
if (isToml) { const isJson = filename.endsWith('.json');
const tomlBlueprint = parse(fileContent); if (isToml) {
const blueprintFromFile = mapOnPremToHosted( const tomlBlueprint = parse(fileContent);
tomlBlueprint as BlueprintItem const blueprintFromFile = mapOnPremToHosted(
); tomlBlueprint as BlueprintItem
const importBlueprintState = mapExportRequestToState(
blueprintFromFile,
[]
);
setIsOnPrem(true);
setImportedBlueprint(importBlueprintState);
} else if (isJson) {
const blueprintFromFile = JSON.parse(fileContent);
try {
const blueprintExportedResponse: BlueprintExportResponse = {
name: blueprintFromFile.name,
description: blueprintFromFile.description,
distribution: blueprintFromFile.distribution,
customizations: blueprintFromFile.customizations,
metadata: blueprintFromFile.metadata,
content_sources: blueprintFromFile.content_sources,
};
const importBlueprintState = mapExportRequestToState(
blueprintExportedResponse,
blueprintFromFile.image_requests || []
); );
if (blueprintExportedResponse.content_sources) {
handleRepositoryImport(blueprintExportedResponse);
}
setIsOnPrem(false);
setImportedBlueprint(importBlueprintState);
} catch {
const blueprintFromFileMapped =
mapOnPremToHosted(blueprintFromFile);
const importBlueprintState = mapExportRequestToState( const importBlueprintState = mapExportRequestToState(
blueprintFromFileMapped, blueprintFromFile,
[] []
); );
setIsOnPrem(true); setIsOnPrem(true);
setImportedBlueprint(importBlueprintState); setImportedBlueprint(importBlueprintState);
} else if (isJson) {
const blueprintFromFile = JSON.parse(fileContent);
let customRepos: CustomRepository[] = [];
try {
if (
blueprintFromFile.content_sources &&
blueprintFromFile.content_sources.length > 0
) {
const imported = await handleRepositoryImport(
blueprintFromFile
);
customRepos = imported ?? [];
}
const blueprintExportedResponse: BlueprintExportResponse = {
name: blueprintFromFile.name,
description: blueprintFromFile.description,
distribution: blueprintFromFile.distribution,
customizations: blueprintFromFile.customizations,
metadata: blueprintFromFile.metadata,
content_sources: blueprintFromFile.content_sources,
};
blueprintExportedResponse.customizations.custom_repositories =
customRepos;
blueprintExportedResponse.customizations.payload_repositories =
undefined;
const importBlueprintState = mapExportRequestToState(
blueprintExportedResponse,
blueprintFromFile.image_requests || []
);
setIsOnPrem(false);
setImportedBlueprint(importBlueprintState);
} catch {
const blueprintFromFileMapped =
mapOnPremToHosted(blueprintFromFile);
const importBlueprintState = mapExportRequestToState(
blueprintFromFileMapped,
[]
);
setIsOnPrem(true);
setImportedBlueprint(importBlueprintState);
}
} }
} catch (error) {
setIsInvalidFormat(true);
dispatch(
addNotification({
variant: 'warning',
title: 'File is not a valid blueprint',
description: error?.data?.error?.message,
})
);
} }
} catch (error) { };
setIsInvalidFormat(true); parseAndImport();
dispatch(
addNotification({
variant: 'warning',
title: 'File is not a valid blueprint',
description: error?.data?.error?.message,
})
);
}
} }
}, [filename, fileContent]); }, [filename, fileContent]);

View file

@ -37,6 +37,7 @@ import {
UploadTypes, UploadTypes,
User, User,
} from '../../../store/imageBuilderApi'; } from '../../../store/imageBuilderApi';
import { ApiRepositoryImportResponseRead } from '../../../store/service/contentSourcesApi';
import { import {
selectActivationKey, selectActivationKey,
selectArchitecture, selectArchitecture,
@ -395,6 +396,24 @@ export const mapRequestToState = (request: BlueprintResponse): wizardState => {
}; };
}; };
export function mapToCustomRepositories(
repo: ApiRepositoryImportResponseRead
): CustomRepository[] {
if (!repo.uuid) return [];
return [
{
id: repo.uuid,
name: repo.name,
baseurl: repo.url ? [repo.url] : undefined,
gpgkey: repo.gpg_key ? [repo.gpg_key] : undefined,
check_gpg: repo.metadata_verification ?? undefined,
check_repo_gpg: repo.metadata_verification ?? undefined,
module_hotfixes: repo.module_hotfixes ?? undefined,
enabled: true,
},
];
}
/** /**
* This function maps the blueprint response to the wizard state, used to populate the wizard with the blueprint details * This function maps the blueprint response to the wizard state, used to populate the wizard with the blueprint details
* @param request BlueprintExportResponse * @param request BlueprintExportResponse