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:
parent
d4436dc6a9
commit
0d4bb26e0f
15 changed files with 82 additions and 60 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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('')}
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ const PackageRecommendations = () => {
|
|||
offset: 0,
|
||||
});
|
||||
|
||||
if (isSuccessDistroRepositories && distroRepositories.data) {
|
||||
if (isSuccessDistroRepositories && distroRepositories?.data) {
|
||||
distroRepoUrls = distroRepositories.data.map((repo) => repo.url || '');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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} />)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()}
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -346,7 +346,7 @@ export const TargetEnvAzureList = () => {
|
|||
</TextListItem>
|
||||
<TextListItem component={TextListItemVariants.dd}>
|
||||
{
|
||||
rawAzureSources.data?.find(
|
||||
rawAzureSources?.data?.find(
|
||||
(source) => source.id === azureSource
|
||||
)?.name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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])) {
|
||||
|
|
|
|||
|
|
@ -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} />}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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(''));
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue