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

View file

@ -37,6 +37,7 @@ import {
UploadTypes,
User,
} from '../../../store/imageBuilderApi';
import { ApiRepositoryImportResponseRead } from '../../../store/service/contentSourcesApi';
import {
selectActivationKey,
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
* @param request BlueprintExportResponse