|
| 1 | +import React, { useState } from 'react'; |
| 2 | + |
| 3 | +import { |
| 4 | + Button, |
| 5 | + ClipboardCopy, |
| 6 | + ClipboardCopyVariant, |
| 7 | + List, |
| 8 | + ListComponent, |
| 9 | + ListItem, |
| 10 | + Modal, |
| 11 | + ModalBody, |
| 12 | + ModalFooter, |
| 13 | + ModalHeader, |
| 14 | + ModalVariant, |
| 15 | + OrderType, |
| 16 | + TextInput, |
| 17 | +} from '@patternfly/react-core'; |
| 18 | +import { ExternalLinkAltIcon } from '@patternfly/react-icons'; |
| 19 | + |
| 20 | +import { generateDefaultName } from './useGenerateDefaultName'; |
| 21 | + |
| 22 | +import { |
| 23 | + ComposesResponseItem, |
| 24 | + ComposeStatus, |
| 25 | +} from '../../store/imageBuilderApi'; |
| 26 | +import { |
| 27 | + isGcpUploadRequestOptions, |
| 28 | + isGcpUploadStatus, |
| 29 | +} from '../../store/typeGuards'; |
| 30 | +import { parseGcpSharedWith } from '../ImagesTable/ImageDetails'; |
| 31 | + |
| 32 | +type LaunchProps = { |
| 33 | + isOpen: boolean; |
| 34 | + handleModalToggle: (event: KeyboardEvent | React.MouseEvent) => void; |
| 35 | + compose: ComposesResponseItem; |
| 36 | + composeStatus: ComposeStatus | undefined; |
| 37 | +}; |
| 38 | + |
| 39 | +export const GcpLaunchModal = ({ |
| 40 | + isOpen, |
| 41 | + handleModalToggle, |
| 42 | + compose, |
| 43 | + composeStatus, |
| 44 | +}: LaunchProps) => { |
| 45 | + const [customerProjectId, setCustomerProjectId] = useState(''); |
| 46 | + |
| 47 | + const statusOptions = composeStatus?.image_status.upload_status?.options; |
| 48 | + const composeOptions = |
| 49 | + compose.request.image_requests[0].upload_request.options; |
| 50 | + |
| 51 | + if ( |
| 52 | + (statusOptions && !isGcpUploadStatus(statusOptions)) || |
| 53 | + !isGcpUploadRequestOptions(composeOptions) |
| 54 | + ) { |
| 55 | + throw TypeError( |
| 56 | + `Error: options must be of type GcpUploadRequestOptions, not ${typeof statusOptions}.`, |
| 57 | + ); |
| 58 | + } |
| 59 | + |
| 60 | + const imageName = statusOptions?.image_name; |
| 61 | + const projectId = statusOptions?.project_id; |
| 62 | + if (!imageName || !projectId) { |
| 63 | + throw TypeError( |
| 64 | + `Error: Image name not found, unable to generate a command to copy ${typeof statusOptions}.`, |
| 65 | + ); |
| 66 | + } |
| 67 | + const uniqueImageName = generateDefaultName(imageName); |
| 68 | + const authorizeString = |
| 69 | + composeOptions.share_with_accounts && |
| 70 | + composeOptions.share_with_accounts.length === 1 |
| 71 | + ? `Authorize gcloud CLI to the following |
| 72 | + account: ${parseGcpSharedWith(composeOptions.share_with_accounts)}.` |
| 73 | + : composeOptions.share_with_accounts |
| 74 | + ? `Authorize gcloud CLI to use one of the following |
| 75 | + accounts: ${parseGcpSharedWith(composeOptions.share_with_accounts)}.` |
| 76 | + : 'Authorize gcloud CLI to use the account that the image is shared with.'; |
| 77 | + const installationCommand = `sudo dnf install google-cloud-cli`; |
| 78 | + const createImage = `gcloud compute images create ${uniqueImageName} --source-image=${imageName} --source-image-project=${projectId} --project=${ |
| 79 | + customerProjectId || '<your_project_id>' |
| 80 | + }`; |
| 81 | + const createInstance = `gcloud compute instances create ${uniqueImageName} --image=${uniqueImageName} --project=${ |
| 82 | + customerProjectId || '<your_project_id>' |
| 83 | + }`; |
| 84 | + return ( |
| 85 | + <Modal |
| 86 | + isOpen={isOpen} |
| 87 | + onClose={handleModalToggle} |
| 88 | + variant={ModalVariant.large} |
| 89 | + aria-label='Open launch guide modal' |
| 90 | + > |
| 91 | + <ModalHeader |
| 92 | + title={'Launch with Google Cloud Platform'} |
| 93 | + labelId='modal-title' |
| 94 | + description={compose.image_name} |
| 95 | + /> |
| 96 | + <ModalBody id='modal-box-body-basic'> |
| 97 | + <List component={ListComponent.ol} type={OrderType.number}> |
| 98 | + <ListItem> |
| 99 | + Install the gcloud CLI. See the{' '} |
| 100 | + <Button |
| 101 | + component='a' |
| 102 | + target='_blank' |
| 103 | + variant='link' |
| 104 | + icon={<ExternalLinkAltIcon />} |
| 105 | + iconPosition='right' |
| 106 | + href={`https://cloud.google.com/sdk/docs/install`} |
| 107 | + className='pf-v6-u-pl-0' |
| 108 | + > |
| 109 | + Install gcloud CLI |
| 110 | + </Button> |
| 111 | + documentation. |
| 112 | + <ClipboardCopy isReadOnly hoverTip='Copy' clickTip='Copied'> |
| 113 | + {installationCommand} |
| 114 | + </ClipboardCopy> |
| 115 | + </ListItem> |
| 116 | + <ListItem>{authorizeString}</ListItem> |
| 117 | + <ListItem> |
| 118 | + Enter your GCP project ID, and run the command to create the image |
| 119 | + in your project. |
| 120 | + <TextInput |
| 121 | + className='pf-v6-u-mt-sm pf-v6-u-mb-md' |
| 122 | + value={customerProjectId} |
| 123 | + type='text' |
| 124 | + onChange={(_event, value) => setCustomerProjectId(value)} |
| 125 | + aria-label='Project ID input' |
| 126 | + placeholder='Project ID' |
| 127 | + /> |
| 128 | + <ClipboardCopy |
| 129 | + isReadOnly |
| 130 | + hoverTip='Copy' |
| 131 | + clickTip='Copied' |
| 132 | + variant={ClipboardCopyVariant.expansion} |
| 133 | + > |
| 134 | + {createImage} |
| 135 | + </ClipboardCopy> |
| 136 | + </ListItem> |
| 137 | + <ListItem> |
| 138 | + Create an instance of your image by either accessing the{' '} |
| 139 | + <Button |
| 140 | + component='a' |
| 141 | + target='_blank' |
| 142 | + variant='link' |
| 143 | + icon={<ExternalLinkAltIcon />} |
| 144 | + iconPosition='right' |
| 145 | + href={`https://console.cloud.google.com/compute/images`} |
| 146 | + className='pf-v6-u-pl-0' |
| 147 | + > |
| 148 | + GCP console |
| 149 | + </Button>{' '} |
| 150 | + or by running the following command: |
| 151 | + <ClipboardCopy |
| 152 | + isReadOnly |
| 153 | + hoverTip='Copy' |
| 154 | + clickTip='Copied' |
| 155 | + variant={ClipboardCopyVariant.expansion} |
| 156 | + > |
| 157 | + {createInstance} |
| 158 | + </ClipboardCopy> |
| 159 | + </ListItem> |
| 160 | + </List> |
| 161 | + </ModalBody> |
| 162 | + <ModalFooter> |
| 163 | + <Button key='close' variant='primary' onClick={handleModalToggle}> |
| 164 | + Close |
| 165 | + </Button> |
| 166 | + </ModalFooter> |
| 167 | + </Modal> |
| 168 | + ); |
| 169 | +}; |
0 commit comments