multiple: check when var is possibly undefined

In cases where a field on an object might be undefined,
rather omit the value than set the field to undefined.
This commit is contained in:
Gianluca Zuccarelli 2024-11-29 14:02:23 +00:00 committed by Lucas Garfield
parent d4436dc6a9
commit 0d4bb26e0f
15 changed files with 82 additions and 60 deletions

View file

@ -11,18 +11,27 @@ import {
setBlueprintsOffset,
} from '../../store/BlueprintSlice';
import { useAppDispatch, useAppSelector } from '../../store/hooks';
import { useGetBlueprintsQuery } from '../../store/imageBuilderApi';
import {
useGetBlueprintsQuery,
GetBlueprintsApiArg,
} from '../../store/imageBuilderApi';
const BlueprintsPagination = () => {
const blueprintSearchInput = useAppSelector(selectBlueprintSearchInput);
const blueprintsOffset = useAppSelector(selectOffset) || 0;
const blueprintsLimit = useAppSelector(selectLimit) || 10;
const currPage = Math.floor(blueprintsOffset / blueprintsLimit) + 1;
const { data: blueprintsData } = useGetBlueprintsQuery({
search: blueprintSearchInput,
const searchParams: GetBlueprintsApiArg = {
limit: blueprintsLimit,
offset: blueprintsOffset,
});
};
if (blueprintSearchInput) {
searchParams.search = blueprintSearchInput;
}
const { data: blueprintsData } = useGetBlueprintsQuery(searchParams);
const dispatch = useAppDispatch();
const blueprintsTotal = blueprintsData?.meta?.count || 0;

View file

@ -41,7 +41,10 @@ import {
} from '../../store/BlueprintSlice';
import { imageBuilderApi } from '../../store/enhancedImageBuilderApi';
import { useAppDispatch, useAppSelector } from '../../store/hooks';
import { BlueprintItem } from '../../store/imageBuilderApi';
import {
BlueprintItem,
GetBlueprintsApiArg,
} from '../../store/imageBuilderApi';
import { resolveRelPath } from '../../Utilities/path';
type blueprintSearchProps = {
@ -61,15 +64,21 @@ const BlueprintsSidebar = () => {
const blueprintSearchInput = useAppSelector(selectBlueprintSearchInput);
const blueprintsOffset = useAppSelector(selectOffset) || PAGINATION_OFFSET;
const blueprintsLimit = useAppSelector(selectLimit) || PAGINATION_LIMIT;
const searchParams: GetBlueprintsApiArg = {
limit: blueprintsLimit,
offset: blueprintsOffset,
};
if (blueprintSearchInput) {
searchParams.search = blueprintSearchInput;
}
const {
data: blueprintsData,
isLoading,
isFetching,
} = useGetBlueprintsQuery({
search: blueprintSearchInput,
limit: blueprintsLimit,
offset: blueprintsOffset,
});
} = useGetBlueprintsQuery(searchParams);
const dispatch = useAppDispatch();
const blueprints = blueprintsData?.data;
@ -189,7 +198,7 @@ const BlueprintSearch = ({ blueprintsTotal }: blueprintSearchProps) => {
return (
<SearchInput
value={blueprintSearchInput}
value={blueprintSearchInput || ''}
placeholder="Search by name or description"
onChange={(_event, value) => onChange(value)}
onClear={() => onChange('')}

View file

@ -18,6 +18,7 @@ import {
import { imageBuilderApi } from '../../store/enhancedImageBuilderApi';
import { useAppDispatch, useAppSelector } from '../../store/hooks';
import {
GetBlueprintsApiArg,
useDeleteBlueprintMutation,
useGetBlueprintsQuery,
} from '../../store/imageBuilderApi';
@ -35,21 +36,24 @@ export const DeleteBlueprintModal: React.FunctionComponent<
const blueprintsOffset = useAppSelector(selectOffset) || PAGINATION_OFFSET;
const blueprintsLimit = useAppSelector(selectLimit) || PAGINATION_LIMIT;
const dispatch = useAppDispatch();
const { blueprintName } = useGetBlueprintsQuery(
{
search: blueprintSearchInput,
limit: blueprintsLimit,
offset: blueprintsOffset,
},
{
selectFromResult: ({ data }) => ({
blueprintName: data?.data?.find(
(blueprint: { id: string | undefined }) =>
blueprint.id === selectedBlueprintId
)?.name,
}),
}
);
const searchParams: GetBlueprintsApiArg = {
limit: blueprintsLimit,
offset: blueprintsOffset,
};
if (blueprintSearchInput) {
searchParams.search = blueprintSearchInput;
}
const { blueprintName } = useGetBlueprintsQuery(searchParams, {
selectFromResult: ({ data }) => ({
blueprintName: data?.data?.find(
(blueprint: { id: string | undefined }) =>
blueprint.id === selectedBlueprintId
)?.name,
}),
});
const [deleteBlueprint] = useDeleteBlueprintMutation({
fixedCacheKey: 'delete-blueprint',
});

View file

@ -62,7 +62,7 @@ const PackageRecommendations = () => {
offset: 0,
});
if (isSuccessDistroRepositories && distroRepositories.data) {
if (isSuccessDistroRepositories && distroRepositories?.data) {
distroRepoUrls = distroRepositories.data.map((repo) => repo.url || '');
}

View file

@ -267,7 +267,7 @@ const Packages = () => {
apiContentUnitSearchRequest: {
search: debouncedSearchTerm,
urls: distroRepositories
.filter((archItem) => {
?.filter((archItem) => {
return archItem.arch === arch;
})[0]
.repositories.flatMap((repo) => {
@ -329,7 +329,7 @@ const Packages = () => {
apiContentUnitSearchRequest: {
search: debouncedSearchTerm.substr(1),
urls: distroRepositories
.filter((archItem) => {
?.filter((archItem) => {
return archItem.arch === arch;
})[0]
.repositories.flatMap((repo) => {
@ -348,7 +348,7 @@ const Packages = () => {
searchCustomGroups({
apiContentUnitSearchRequest: {
search: debouncedSearchTerm.substr(1),
urls: customRepositories.flatMap((repo) => {
urls: customRepositories?.flatMap((repo) => {
if (!repo.baseurl) {
throw new Error(
`Repository (id: ${repo.id}, name: ${repo?.name}) is missing baseurl`
@ -824,7 +824,7 @@ const Packages = () => {
if (isSelecting) {
if (
isSuccessEpelRepo &&
epelRepo.data &&
epelRepo?.data &&
pkg.repository === 'recommended' &&
!recommendedRepositories.some((repo) => repo.name?.startsWith('EPEL'))
) {
@ -837,7 +837,7 @@ const Packages = () => {
dispatch(removePackage(pkg.name));
if (
isSuccessEpelRepo &&
epelRepo.data &&
epelRepo?.data &&
packages.filter((pkg) => pkg.repository === 'recommended').length ===
1 &&
groups.filter((grp) => grp.repository === 'recommended').length === 0
@ -855,7 +855,7 @@ const Packages = () => {
if (isSelecting) {
if (
isSuccessEpelRepo &&
epelRepo.data &&
epelRepo?.data &&
grp.repository === 'recommended' &&
!recommendedRepositories.some((repo) => repo.name?.startsWith('EPEL'))
) {
@ -868,7 +868,7 @@ const Packages = () => {
dispatch(removeGroup(grp.name));
if (
isSuccessEpelRepo &&
epelRepo.data &&
epelRepo?.data &&
groups.filter((grp) => grp.repository === 'recommended').length === 1 &&
packages.filter((pkg) => pkg.repository === 'recommended').length === 0
) {

View file

@ -50,19 +50,19 @@ const ActivationKeyInformation = (): JSX.Element => {
Role:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKeyInfo.body?.role || 'Not defined'}
{activationKeyInfo?.body?.role || 'Not defined'}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
SLA:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKeyInfo.body?.serviceLevel || 'Not defined'}
{activationKeyInfo?.body?.serviceLevel || 'Not defined'}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Usage:
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{activationKeyInfo.body?.usage || 'Not defined'}
{activationKeyInfo?.body?.usage || 'Not defined'}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Additional repositories:
@ -90,8 +90,8 @@ const ActivationKeyInformation = (): JSX.Element => {
component={TextListItemVariants.dd}
className="pf-v5-u-display-flex pf-v5-u-align-items-flex-end"
>
{activationKeyInfo.body?.additionalRepositories &&
activationKeyInfo.body?.additionalRepositories?.length > 0 ? (
{activationKeyInfo?.body?.additionalRepositories &&
activationKeyInfo?.body?.additionalRepositories?.length > 0 ? (
<Popover
position="right"
minWidth="30rem"

View file

@ -157,7 +157,7 @@ const ActivationKeysList = () => {
const isActivationKeysEmpty =
isSuccessActivationKeys &&
!isLoadingActivationKey &&
activationKeys.body?.length === 0;
activationKeys?.body?.length === 0;
const handleCreateActivationKey = async () => {
try {
@ -207,7 +207,7 @@ const ActivationKeysList = () => {
const setSelectOptions = () => {
const selectOptions = [];
if (isSuccessActivationKeys) {
activationKeys.body?.map((key, index) =>
activationKeys?.body?.map((key, index) =>
selectOptions.push(<SelectOption key={index} value={key.name} />)
);
}

View file

@ -64,8 +64,8 @@ const RepoName = ({ repoUrl }: repoPropType) => {
- query finished and the repo was found -> render the name of the repo
- query finished, but the repo was not found -> render an error
*/}
{isSuccess && data.data?.[0]?.name && <p>{data.data?.[0].name}</p>}
{isSuccess && !data.data?.[0]?.name && errorLoading()}
{isSuccess && data?.data?.[0]?.name && <p>{data.data?.[0].name}</p>}
{isSuccess && !data?.data?.[0]?.name && errorLoading()}
{isFetching && <Spinner size="md" />}
{isError && errorLoading()}
</>

View file

@ -346,7 +346,7 @@ export const TargetEnvAzureList = () => {
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{
rawAzureSources.data?.find(
rawAzureSources?.data?.find(
(source) => source.id === azureSource
)?.name
}

View file

@ -64,7 +64,7 @@ export const useCheckRepositoriesAvailability = () => {
// Transform the fresh repos array into a Set to access its elements in O(1)
// complexity later in the for loop.
const freshReposUrls = new Set(
freshRepos.data?.map((freshRepo) => freshRepo.url)
freshRepos?.data?.map((freshRepo) => freshRepo.url)
);
for (const customRepo of customRepositories) {
if (customRepo.baseurl && !freshReposUrls.has(customRepo.baseurl[0])) {

View file

@ -107,7 +107,7 @@ const ComposeRow = ({ compose }: ComposeRowPropTypes) => {
});
return isSuccess ? (
<Row
ami={<Ami status={data.image_status.upload_status} />}
ami={<Ami status={data?.image_status.upload_status} />}
region={<ComposeRegion />}
status={<AwsDetailsStatus compose={compose} />}
/>

View file

@ -103,7 +103,7 @@ const ImagesTableToolbar: React.FC<imagesTableToolbarProps> = ({
const isBlueprintDistroCentos8 = () => {
if (isSuccessBlueprintsCompose) {
return (
blueprintsComposes.data[0].request.distribution ===
blueprintsComposes?.data[0].request.distribution ===
('centos-8' as Distributions)
);
}

View file

@ -124,7 +124,7 @@ const ProvisioningLink = ({
if (
error ||
!exposedScalprumModule ||
composeStatus.image_status.status !== 'success'
composeStatus?.image_status.status !== 'success'
) {
return <DisabledProvisioningLink />;
} else {
@ -243,7 +243,7 @@ export const OciInstance = ({ compose, isExpired }: OciInstancePropTypes) => {
return <Skeleton />;
}
const options = data.image_status.upload_status?.options;
const options = data?.image_status.upload_status?.options;
if (options && !isOciUploadStatus(options)) {
throw TypeError(
@ -375,8 +375,8 @@ export const AwsS3Instance = ({
oci: '',
};
const status = composeStatus.image_status.status;
const options = composeStatus.image_status.upload_status?.options;
const status = composeStatus?.image_status.status;
const options = composeStatus?.image_status.upload_status?.options;
if (options && !isAwss3UploadStatus(options)) {
throw TypeError(

View file

@ -78,7 +78,7 @@ export const AwsDetailsStatus = ({ compose }: ComposeStatusPropTypes) => {
return <></>;
}
switch (data.image_status.status) {
switch (data?.image_status.status) {
case 'failure':
return (
<ErrorStatus
@ -90,8 +90,8 @@ export const AwsDetailsStatus = ({ compose }: ComposeStatusPropTypes) => {
default:
return (
<Status
icon={statuses[data.image_status.status].icon}
text={statuses[data.image_status.status].text}
icon={statuses[data!.image_status.status].icon}
text={statuses[data!.image_status.status].text}
/>
);
}
@ -110,7 +110,7 @@ export const CloudStatus = ({ compose }: CloudStatusPropTypes) => {
return <Skeleton />;
}
switch (data.image_status.status) {
switch (data?.image_status.status) {
case 'failure':
return (
<ErrorStatus
@ -122,8 +122,8 @@ export const CloudStatus = ({ compose }: CloudStatusPropTypes) => {
default:
return (
<Status
icon={statuses[data.image_status.status].icon}
text={statuses[data.image_status.status].text}
icon={statuses[data!.image_status.status].icon}
text={statuses[data!.image_status.status].text}
/>
);
}
@ -172,7 +172,7 @@ export const ExpiringStatus = ({
return <Skeleton />;
}
const status = composeStatus.image_status.status;
const status = composeStatus!.image_status.status;
const remainingHours = AWS_S3_EXPIRATION_TIME_IN_HOURS - timeToExpiration;
const remainingDays = OCI_STORAGE_EXPIRATION_TIME_IN_DAYS - timeToExpiration;
@ -205,7 +205,7 @@ export const ExpiringStatus = ({
<ErrorStatus
icon={statuses[status].icon}
text={statuses[status].text}
error={composeStatus.image_status.error || ''}
error={composeStatus?.image_status.error || ''}
/>
);
} else {

View file

@ -142,7 +142,7 @@ const RegionsSelect = ({ composeId, handleClose }: RegionsSelectPropTypes) => {
const handleSubmit = async () => {
setIsSaving(true);
const requests = generateRequests(composeId, composeStatus, selected);
const requests = generateRequests(composeId, composeStatus!, selected);
await Promise.allSettled(requests.map((request) => cloneCompose(request)));
navigate(resolveRelPath(''));
};