This adds a row for OCI images in the ImagesTable. Details about the images show UUID of the image and the Object Storage URL which is needed to deploy the image. "Image link" button in the Instance column contains instrucion on how to run an OCI image built by Image Builder in Oracle Cloud. The documentation link in the popover is just a placeholder for now as the documentation is being prepared. Until the build is finished the "Image link" button is disabled as it would be missing the Object Storage URL which is creating on upload.
450 lines
13 KiB
TypeScript
450 lines
13 KiB
TypeScript
import React from 'react';
|
|
|
|
import {
|
|
ClipboardCopy,
|
|
DescriptionList,
|
|
DescriptionListGroup,
|
|
DescriptionListDescription,
|
|
DescriptionListTerm,
|
|
Button,
|
|
Popover,
|
|
Alert,
|
|
Skeleton,
|
|
} from '@patternfly/react-core';
|
|
import { ExternalLinkAltIcon } from '@patternfly/react-icons';
|
|
|
|
import ClonesTable from './ClonesTable';
|
|
|
|
import { extractProvisioningList } from '../../store/helpers';
|
|
import {
|
|
ComposesResponseItem,
|
|
GcpUploadRequestOptions,
|
|
useGetComposeStatusQuery,
|
|
} from '../../store/imageBuilderApi';
|
|
import { useGetSourceListQuery } from '../../store/provisioningApi';
|
|
import {
|
|
isAwsUploadRequestOptions,
|
|
isAzureUploadRequestOptions,
|
|
isAzureUploadStatus,
|
|
isGcpUploadRequestOptions,
|
|
isGcpUploadStatus,
|
|
isOciUploadStatus,
|
|
} from '../../store/typeGuards';
|
|
|
|
const SourceNotFoundPopover = () => {
|
|
return (
|
|
<Popover
|
|
position="bottom"
|
|
bodyContent={
|
|
<>
|
|
<Alert
|
|
variant="danger"
|
|
title="Source name cannot be loaded"
|
|
className="pf-u-pb-md"
|
|
isInline
|
|
isPlain
|
|
/>
|
|
<p>
|
|
The information about the source cannot be loaded. Please check the
|
|
source was not removed and try again later.
|
|
</p>
|
|
<br />
|
|
<Button
|
|
component="a"
|
|
target="_blank"
|
|
variant="link"
|
|
icon={<ExternalLinkAltIcon />}
|
|
iconPosition="right"
|
|
isInline
|
|
href={'settings/sources'}
|
|
>
|
|
Manage sources here
|
|
</Button>
|
|
</>
|
|
}
|
|
>
|
|
<Button variant="link" className="pf-u-p-0 pf-u-font-size-sm">
|
|
<div className="failure-button">Source name cannot be loaded</div>
|
|
</Button>
|
|
</Popover>
|
|
);
|
|
};
|
|
|
|
type AzureSourceNamePropTypes = {
|
|
id: string;
|
|
};
|
|
|
|
const AzureSourceName = ({ id }: AzureSourceNamePropTypes) => {
|
|
const { data: rawSources, isSuccess } = useGetSourceListQuery({
|
|
provider: 'azure',
|
|
});
|
|
|
|
if (!isSuccess) {
|
|
return <Skeleton />;
|
|
}
|
|
|
|
const sources = extractProvisioningList(rawSources);
|
|
|
|
const sourcename = sources?.find((source) => source.id === id);
|
|
if (sourcename) {
|
|
return <p>{sourcename.name}</p>;
|
|
} else {
|
|
return <SourceNotFoundPopover />;
|
|
}
|
|
};
|
|
|
|
type AwsSourceNamePropTypes = {
|
|
id: string;
|
|
};
|
|
|
|
const AwsSourceName = ({ id }: AwsSourceNamePropTypes) => {
|
|
const { data: rawSources, isSuccess } = useGetSourceListQuery({
|
|
provider: 'aws',
|
|
});
|
|
|
|
if (!isSuccess) {
|
|
return <Skeleton />;
|
|
}
|
|
|
|
const sources = extractProvisioningList(rawSources);
|
|
|
|
const sourcename = sources?.find((source) => source.id === id);
|
|
if (sourcename) {
|
|
return <p>{sourcename.name}</p>;
|
|
} else {
|
|
return <SourceNotFoundPopover />;
|
|
}
|
|
};
|
|
|
|
const parseGcpSharedWith = (
|
|
sharedWith: GcpUploadRequestOptions['share_with_accounts']
|
|
) => {
|
|
if (sharedWith) {
|
|
const splitGCPSharedWith = sharedWith[0].split(':');
|
|
return splitGCPSharedWith[1];
|
|
}
|
|
};
|
|
|
|
type AwsDetailsPropTypes = {
|
|
compose: ComposesResponseItem;
|
|
};
|
|
|
|
export const AwsDetails = ({ compose }: AwsDetailsPropTypes) => {
|
|
const options = compose.request.image_requests[0].upload_request.options;
|
|
|
|
if (!isAwsUploadRequestOptions(options)) {
|
|
throw TypeError(
|
|
`Error: options must be of type AwsUploadRequestOptions, not ${typeof options}.`
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">Build Information</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>UUID</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
ouiaId="aws-uuid"
|
|
>
|
|
{compose.id}
|
|
</ClipboardCopy>
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
{options.share_with_sources?.[0] && (
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Source</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<AwsSourceName id={options.share_with_sources[0]} />
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
)}
|
|
{options.share_with_accounts?.[0] && (
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Shared with</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<Button
|
|
component="a"
|
|
target="_blank"
|
|
variant="link"
|
|
icon={<ExternalLinkAltIcon />}
|
|
iconPosition="right"
|
|
isInline
|
|
// the format of an account link is taken from
|
|
// https://docs.aws.amazon.com/signin/latest/userguide/sign-in-urls-defined.html
|
|
href={`https://${options.share_with_accounts[0]}.signin.aws.amazon.com/console/`}
|
|
>
|
|
{options.share_with_accounts[0]}
|
|
</Button>
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
)}
|
|
</DescriptionList>
|
|
<>
|
|
<br />
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">
|
|
Cloud Provider Identifiers
|
|
</div>
|
|
</>
|
|
<ClonesTable compose={compose} />
|
|
</>
|
|
);
|
|
};
|
|
|
|
type AzureDetailsPropTypes = {
|
|
compose: ComposesResponseItem;
|
|
};
|
|
|
|
export const AzureDetails = ({ compose }: AzureDetailsPropTypes) => {
|
|
const { data: composeStatus } = useGetComposeStatusQuery({
|
|
composeId: compose.id,
|
|
});
|
|
|
|
const options = compose.request.image_requests[0].upload_request.options;
|
|
|
|
if (!isAzureUploadRequestOptions(options)) {
|
|
throw TypeError(
|
|
`Error: options must be of type AzureUploadRequestOptions, not ${typeof options}.`
|
|
);
|
|
}
|
|
|
|
const sourceId = options.source_id;
|
|
const resourceGroup = options.resource_group;
|
|
|
|
const uploadStatus = composeStatus?.image_status.upload_status?.options;
|
|
|
|
if (uploadStatus && !isAzureUploadStatus(uploadStatus)) {
|
|
throw TypeError(
|
|
`Error: uploadStatus must be of type AzureUploadStatus, not ${typeof uploadStatus}.`
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">Build Information</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>UUID</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
ouiaId="azure-uuid"
|
|
>
|
|
{compose.id}
|
|
</ClipboardCopy>
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
{sourceId && (
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Source</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<AzureSourceName id={sourceId} />
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
)}
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Resource Group</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
{resourceGroup}
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
</DescriptionList>
|
|
<br />
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">
|
|
Cloud Provider Identifiers
|
|
</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Image name</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
{composeStatus?.image_status.status === 'success' && (
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
>
|
|
{uploadStatus?.image_name}
|
|
</ClipboardCopy>
|
|
)}
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
</DescriptionList>
|
|
</>
|
|
);
|
|
};
|
|
|
|
type GcpDetailsPropTypes = {
|
|
compose: ComposesResponseItem;
|
|
};
|
|
|
|
export const GcpDetails = ({ compose }: GcpDetailsPropTypes) => {
|
|
const { data: composeStatus } = useGetComposeStatusQuery({
|
|
composeId: compose.id,
|
|
});
|
|
|
|
const options = compose.request.image_requests[0].upload_request.options;
|
|
|
|
if (!isGcpUploadRequestOptions(options)) {
|
|
throw TypeError(
|
|
`Error: options must be of type GcpUploadRequestOptions, not ${typeof options}.`
|
|
);
|
|
}
|
|
|
|
const uploadStatus = composeStatus?.image_status.upload_status?.options;
|
|
|
|
if (uploadStatus && !isGcpUploadStatus(uploadStatus)) {
|
|
throw TypeError(
|
|
`Error: uploadStatus must be of type GcpUploadStatus, not ${typeof uploadStatus}.`
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">Build Information</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>UUID</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
ouiaId="gcp-uuid"
|
|
>
|
|
{compose.id}
|
|
</ClipboardCopy>
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
{composeStatus?.image_status.status === 'success' && (
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Project ID</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
{uploadStatus?.project_id}
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
)}
|
|
{options.share_with_accounts && (
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Shared with</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
{parseGcpSharedWith(options.share_with_accounts)}
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
)}
|
|
</DescriptionList>
|
|
<br />
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">
|
|
Cloud Provider Identifiers
|
|
</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Image name</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
{composeStatus?.image_status.status === 'success' && (
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
>
|
|
{uploadStatus?.image_name}
|
|
</ClipboardCopy>
|
|
)}
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
</DescriptionList>
|
|
</>
|
|
);
|
|
};
|
|
|
|
type OciDetailsPropTypes = {
|
|
compose: ComposesResponseItem;
|
|
};
|
|
|
|
export const OciDetails = ({ compose }: OciDetailsPropTypes) => {
|
|
const { data: composeStatus } = useGetComposeStatusQuery({
|
|
composeId: compose.id,
|
|
});
|
|
|
|
const options = composeStatus?.image_status.upload_status?.options;
|
|
|
|
if (options && !isOciUploadStatus(options)) {
|
|
throw TypeError(
|
|
`Error: uploadStatus must be of type OciUploadStatus, not ${typeof options}.`
|
|
);
|
|
}
|
|
|
|
return (
|
|
<>
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">Build Information</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>UUID</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
ouiaId="gcp-uuid"
|
|
>
|
|
{compose.id}
|
|
</ClipboardCopy>
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
</DescriptionList>
|
|
<br />
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">
|
|
Cloud Provider Identifiers
|
|
</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>Object Storage URL</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
{composeStatus?.image_status.status === 'success' && (
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
isBlock
|
|
>
|
|
{options?.url}
|
|
</ClipboardCopy>
|
|
)}
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
</DescriptionList>
|
|
</>
|
|
);
|
|
};
|
|
|
|
type AwsS3DetailsPropTypes = {
|
|
compose: ComposesResponseItem;
|
|
};
|
|
|
|
export const AwsS3Details = ({ compose }: AwsS3DetailsPropTypes) => {
|
|
return (
|
|
<>
|
|
<div className="pf-u-font-weight-bold pf-u-pb-md">Build Information</div>
|
|
<DescriptionList isHorizontal isCompact className=" pf-u-pl-xl">
|
|
<DescriptionListGroup>
|
|
<DescriptionListTerm>UUID</DescriptionListTerm>
|
|
<DescriptionListDescription>
|
|
<ClipboardCopy
|
|
hoverTip="Copy"
|
|
clickTip="Copied"
|
|
variant="inline-compact"
|
|
ouiaId="other-targets-uuid"
|
|
>
|
|
{compose.id}
|
|
</ClipboardCopy>
|
|
</DescriptionListDescription>
|
|
</DescriptionListGroup>
|
|
</DescriptionList>
|
|
</>
|
|
);
|
|
};
|