diff --git a/packages/manager/.changeset/pr-11303-fixed-1733422977888.md b/packages/manager/.changeset/pr-11303-fixed-1733422977888.md new file mode 100644 index 00000000000..6819bf30796 --- /dev/null +++ b/packages/manager/.changeset/pr-11303-fixed-1733422977888.md @@ -0,0 +1,5 @@ +--- +"@linode/manager": Fixed +--- + +Incorrect Cloning Commands in Linode CLI Modal ([#11303](https://github.com/linode/manager/pull/11303)) diff --git a/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/ApiAwarenessModal.test.tsx b/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/ApiAwarenessModal.test.tsx index 75acedc1b43..ad88f63e3cc 100644 --- a/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/ApiAwarenessModal.test.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/ApiAwarenessModal.test.tsx @@ -2,10 +2,11 @@ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import React from 'react'; -import { renderWithTheme } from 'src/utilities/testHelpers'; +import { renderWithThemeAndHookFormContext } from 'src/utilities/testHelpers'; import { ApiAwarenessModal } from './ApiAwarenessModal'; +import type { LinodeCreateFormValues } from '../utilities'; import type { ApiAwarenessModalProps } from './ApiAwarenessModal'; const defaultProps: ApiAwarenessModalProps = { @@ -19,19 +20,22 @@ const renderComponent = (overrideProps?: Partial) => { ...defaultProps, ...overrideProps, }; - return renderWithTheme(); + + return renderWithThemeAndHookFormContext({ + component: , + }); }; describe('ApiAwarenessModal', () => { - it('Should not render ApiAwarenessModal componet', () => { + it('Should not render ApiAwarenessModal component', () => { renderComponent(); expect(screen.queryByText('Create Linode')).not.toBeInTheDocument(); }); - it('Should render ApiAwarenessModal componet when enabled', () => { + it('Should render ApiAwarenessModal component when enabled', () => { renderComponent({ isOpen: true }); screen.getByText('Create Linode'); }); - it('Should invoke onClose handler upon cliking close button', async () => { + it('Should invoke onClose handler upon clicking close button', async () => { renderComponent({ isOpen: true }); await userEvent.click(screen.getByTestId('close-button')); expect(defaultProps.onClose).toHaveBeenCalledTimes(1); diff --git a/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/CurlTabPanel.tsx b/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/CurlTabPanel.tsx index 08750eb12ac..a9a7ffa38d6 100644 --- a/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/CurlTabPanel.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/CurlTabPanel.tsx @@ -1,6 +1,7 @@ import { Typography } from '@linode/ui'; import { useTheme } from '@mui/material/styles'; import React, { useMemo } from 'react'; +import { useFormContext } from 'react-hook-form'; import { CodeBlock } from 'src/components/CodeBlock/CodeBlock'; import { Link } from 'src/components/Link'; @@ -8,6 +9,9 @@ import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel'; import { sendApiAwarenessClickEvent } from 'src/utilities/analytics/customEventAnalytics'; import { generateCurlCommand } from 'src/utilities/codesnippets/generate-cURL'; +import { useLinodeCreateQueryParams } from '../utilities'; + +import type { LinodeCreateFormValues } from '../utilities'; import type { CreateLinodeRequest } from '@linode/api-v4/lib/linodes'; export interface CurlTabPanelProps { @@ -19,10 +23,20 @@ export interface CurlTabPanelProps { export const CurlTabPanel = ({ index, payLoad, title }: CurlTabPanelProps) => { const theme = useTheme(); - const curlCommand = useMemo( - () => generateCurlCommand(payLoad, '/linode/instances'), - [payLoad] - ); + const { getValues } = useFormContext(); + const sourceLinodeID = getValues('linode.id'); + + const { params } = useLinodeCreateQueryParams(); + const linodeCLIAction = params.type === 'Clone Linode' ? 'clone' : 'create'; + const path = + linodeCLIAction === 'create' + ? '/linode/instances' + : `/linode/instances/${sourceLinodeID}/clone`; + + const curlCommand = useMemo(() => generateCurlCommand(payLoad, path), [ + path, + payLoad, + ]); return ( diff --git a/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/LinodeCLIPanel.tsx b/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/LinodeCLIPanel.tsx index f4d4f3101da..67dfde871e0 100644 --- a/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/LinodeCLIPanel.tsx +++ b/packages/manager/src/features/Linodes/LinodeCreate/ApiAwarenessModal/LinodeCLIPanel.tsx @@ -1,5 +1,6 @@ import { Typography } from '@linode/ui'; import React, { useMemo } from 'react'; +import { useFormContext } from 'react-hook-form'; import { CodeBlock } from 'src/components/CodeBlock/CodeBlock'; import { Link } from 'src/components/Link'; @@ -7,6 +8,9 @@ import { SafeTabPanel } from 'src/components/Tabs/SafeTabPanel'; import { sendApiAwarenessClickEvent } from 'src/utilities/analytics/customEventAnalytics'; import { generateCLICommand } from 'src/utilities/codesnippets/generate-cli'; +import { useLinodeCreateQueryParams } from '../utilities'; + +import type { LinodeCreateFormValues } from '../utilities'; import type { CreateLinodeRequest } from '@linode/api-v4/lib/linodes'; export interface LinodeCLIPanelProps { @@ -20,7 +24,16 @@ export const LinodeCLIPanel = ({ payLoad, title, }: LinodeCLIPanelProps) => { - const cliCommand = useMemo(() => generateCLICommand(payLoad), [payLoad]); + const { params } = useLinodeCreateQueryParams(); + const linodeCLIAction = params.type; + + const { getValues } = useFormContext(); + const sourceLinodeID = getValues('linode.id'); + + const cliCommand = useMemo( + () => generateCLICommand(payLoad, sourceLinodeID, linodeCLIAction), + [linodeCLIAction, payLoad, sourceLinodeID] + ); return ( diff --git a/packages/manager/src/utilities/codesnippets/generate-cli.ts b/packages/manager/src/utilities/codesnippets/generate-cli.ts index 088016e5107..aea5a483275 100644 --- a/packages/manager/src/utilities/codesnippets/generate-cli.ts +++ b/packages/manager/src/utilities/codesnippets/generate-cli.ts @@ -1,10 +1,9 @@ -import { +import type { PlacementGroup } from '@linode/api-v4'; +import type { ConfigInterfaceIPv4, UserData, } from '@linode/api-v4/lib/linodes/types'; -import type { PlacementGroup } from '@linode/api-v4'; - // Credit: https://github.com/xxorax/node-shell-escape function escapeStringForCLI(s: string): string { if (/[^A-Za-z0-9_\/:=-]/.test(s)) { @@ -111,7 +110,18 @@ const dataEntriesReduce = (acc: string[], [key, value]: JSONFieldToArray) => { return acc; }; -export const generateCLICommand = (data: {}) => { +export const generateCLICommand = ( + data: {}, + sourceLinodeID?: number, + linodeCLIAction?: string +) => { const dataForCLI = Object.entries(data).reduce(dataEntriesReduce, []); + + if (linodeCLIAction === 'Clone Linode') { + return `linode-cli linodes clone ${sourceLinodeID} \\\n${dataForCLI.join( + ' \\\n' + )}`; + } + return `linode-cli linodes create \\\n${dataForCLI.join(' \\\n')}`; };