-
Notifications
You must be signed in to change notification settings - Fork 364
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
upcoming: [M3-7944] - Linode Create Refactor - User Data - Part 7 (#1…
…0331) * initial work * unit testing * clean up * fix placement of `.` * Added changeset: Linode Create Refactor v2 - User Data - Part 7 * Update packages/manager/src/features/Linodes/LinodeCreatev2/UserData/UserData.tsx Co-authored-by: Hussain Khalil <122488130+hkhalil-akamai@users.noreply.github.com> * add some bais testing to encode and decode * improve spacing * use flex spacing insted of margin * stop propogation of tooltip icon button click * add a transform step in the onSubmit --------- Co-authored-by: Banks Nussman <banks@nussman.us> Co-authored-by: Hussain Khalil <122488130+hkhalil-akamai@users.noreply.github.com>
- Loading branch information
1 parent
4791fe3
commit 0e0e5a5
Showing
10 changed files
with
359 additions
and
6 deletions.
There are no files selected for viewing
5 changes: 5 additions & 0 deletions
5
packages/manager/.changeset/pr-10331-upcoming-features-1711738458511.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@linode/manager": Upcoming Features | ||
--- | ||
|
||
Linode Create Refactor v2 - User Data - Part 7 ([#10331](https://github.com/linode/manager/pull/10331)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
63 changes: 63 additions & 0 deletions
63
packages/manager/src/features/Linodes/LinodeCreatev2/UserData/UserData.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import { fireEvent } from '@testing-library/react'; | ||
import * as React from 'react'; | ||
|
||
import { imageFactory, regionFactory } from 'src/factories'; | ||
import { makeResourcePage } from 'src/mocks/serverHandlers'; | ||
import { HttpResponse, http, server } from 'src/mocks/testServer'; | ||
import { renderWithThemeAndHookFormContext } from 'src/utilities/testHelpers'; | ||
|
||
import { UserData } from './UserData'; | ||
|
||
describe('Linode Create v2 UserData', () => { | ||
it('should render if the selected image supports cloud-init and the region supports metadata', async () => { | ||
const image = imageFactory.build({ capabilities: ['cloud-init'] }); | ||
const region = regionFactory.build({ capabilities: ['Metadata'] }); | ||
|
||
server.use( | ||
http.get('*/v4/images/*', () => { | ||
return HttpResponse.json(image); | ||
}), | ||
http.get('*/v4/regions', () => { | ||
return HttpResponse.json(makeResourcePage([region])); | ||
}) | ||
); | ||
|
||
const { findByText } = renderWithThemeAndHookFormContext({ | ||
component: <UserData />, | ||
useFormOptions: { defaultValues: { image: image.id, region: region.id } }, | ||
}); | ||
|
||
const userDataHeading = await findByText('Add User Data'); | ||
|
||
expect(userDataHeading).toBeVisible(); | ||
expect(userDataHeading.tagName).toBe('H2'); | ||
}); | ||
|
||
it('should display a warning message if the user data is not in an accepted format', async () => { | ||
const image = imageFactory.build({ capabilities: ['cloud-init'] }); | ||
const region = regionFactory.build({ capabilities: ['Metadata'] }); | ||
|
||
server.use( | ||
http.get('*/v4/images/*', () => { | ||
return HttpResponse.json(image); | ||
}), | ||
http.get('*/v4/regions', () => { | ||
return HttpResponse.json(makeResourcePage([region])); | ||
}) | ||
); | ||
|
||
const inputValue = '#test-string'; | ||
const { findByLabelText, getByText } = renderWithThemeAndHookFormContext({ | ||
component: <UserData />, | ||
useFormOptions: { defaultValues: { image: image.id, region: region.id } }, | ||
}); | ||
|
||
const input = await findByLabelText('User Data'); | ||
fireEvent.change(input, { target: { value: inputValue } }); | ||
fireEvent.blur(input); // triggers format check | ||
|
||
expect( | ||
getByText('The user data may be formatted incorrectly.') | ||
).toBeInTheDocument(); | ||
}); | ||
}); |
111 changes: 111 additions & 0 deletions
111
packages/manager/src/features/Linodes/LinodeCreatev2/UserData/UserData.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import React, { useMemo } from 'react'; | ||
import { Controller, useFormContext, useWatch } from 'react-hook-form'; | ||
|
||
import { Accordion } from 'src/components/Accordion'; | ||
import { Link } from 'src/components/Link'; | ||
import { Notice } from 'src/components/Notice/Notice'; | ||
import { TextField } from 'src/components/TextField'; | ||
import { Typography } from 'src/components/Typography'; | ||
import { useRestrictedGlobalGrantCheck } from 'src/hooks/useRestrictedGlobalGrantCheck'; | ||
import { useImageQuery } from 'src/queries/images'; | ||
import { useRegionsQuery } from 'src/queries/regions/regions'; | ||
|
||
import { UserDataHeading } from './UserDataHeading'; | ||
|
||
import type { CreateLinodeRequest } from '@linode/api-v4'; | ||
|
||
export const UserData = () => { | ||
const { control } = useFormContext<CreateLinodeRequest>(); | ||
|
||
const regionId = useWatch({ control, name: 'region' }); | ||
const imageId = useWatch({ control, name: 'image' }); | ||
|
||
const [formatWarning, setFormatWarning] = React.useState(false); | ||
|
||
const { data: regions } = useRegionsQuery(); | ||
const { data: image } = useImageQuery(imageId ?? '', Boolean(imageId)); | ||
|
||
const checkFormat = ({ | ||
hasInputValueChanged, | ||
userData, | ||
}: { | ||
hasInputValueChanged: boolean; | ||
userData: string; | ||
}) => { | ||
const userDataLower = userData.toLowerCase(); | ||
const validPrefixes = ['#cloud-config', 'content-type: text/', '#!/bin/']; | ||
const isUserDataValid = validPrefixes.some((prefix) => | ||
userDataLower.startsWith(prefix) | ||
); | ||
setFormatWarning( | ||
userData.length > 0 && !isUserDataValid && !hasInputValueChanged | ||
); | ||
}; | ||
|
||
const region = useMemo(() => regions?.find((r) => r.id === regionId), [ | ||
regions, | ||
regionId, | ||
]); | ||
|
||
const isLinodeCreateRestricted = useRestrictedGlobalGrantCheck({ | ||
globalGrantType: 'add_linodes', | ||
}); | ||
|
||
if (!region?.capabilities.includes('Metadata')) { | ||
return null; | ||
} | ||
|
||
if (!image?.capabilities.includes('cloud-init')) { | ||
return null; | ||
} | ||
|
||
return ( | ||
<Accordion heading={<UserDataHeading />} sx={{ m: '0 !important', p: 1 }}> | ||
<Typography> | ||
User data is a feature of the Metadata service that enables you to | ||
perform system configuration tasks (such as adding users and installing | ||
software) by providing custom instructions or scripts to cloud-init. Any | ||
user data should be added at this step and cannot be modified after the | ||
the Linode has been created.{' '} | ||
<Link to="https://www.linode.com/docs/products/compute/compute-instances/guides/metadata/"> | ||
Learn more | ||
</Link> | ||
. | ||
</Typography> | ||
{formatWarning && ( | ||
<Notice spacingBottom={16} spacingTop={16} variant="warning"> | ||
The user data may be formatted incorrectly. | ||
</Notice> | ||
)} | ||
<Controller | ||
render={({ field, fieldState }) => ( | ||
<TextField | ||
onBlur={(e) => | ||
checkFormat({ | ||
hasInputValueChanged: false, | ||
userData: e.target.value, | ||
}) | ||
} | ||
onChange={(e) => { | ||
checkFormat({ | ||
hasInputValueChanged: true, | ||
userData: e.target.value, | ||
}); | ||
field.onChange(e); | ||
}} | ||
disabled={isLinodeCreateRestricted} | ||
errorText={fieldState.error?.message} | ||
expand | ||
label="User Data" | ||
labelTooltipText="Compatible formats include cloud-config data and executable scripts." | ||
multiline | ||
rows={1} | ||
value={field.value ?? ''} | ||
/> | ||
)} | ||
control={control} | ||
name="metadata.user_data" | ||
/> | ||
</Accordion> | ||
); | ||
}; |
35 changes: 35 additions & 0 deletions
35
packages/manager/src/features/Linodes/LinodeCreatev2/UserData/UserDataHeading.test.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import React from 'react'; | ||
|
||
import { renderWithTheme } from 'src/utilities/testHelpers'; | ||
|
||
import { UserDataHeading } from './UserDataHeading'; | ||
|
||
describe('UserDataHeading', () => { | ||
it('should display a warning in the header for cloning', () => { | ||
const { getByText } = renderWithTheme(<UserDataHeading />, { | ||
MemoryRouter: { | ||
initialEntries: ['/linodes/create?type=Clone+Linode'], | ||
}, | ||
}); | ||
|
||
expect( | ||
getByText( | ||
'Existing user data is not cloned. You may add new user data now.' | ||
) | ||
).toBeVisible(); | ||
}); | ||
|
||
it('should display a warning in the header for creating from a Linode backup', () => { | ||
const { getByText } = renderWithTheme(<UserDataHeading />, { | ||
MemoryRouter: { | ||
initialEntries: ['/linodes/create?type=Backups'], | ||
}, | ||
}); | ||
|
||
expect( | ||
getByText( | ||
'Existing user data is not accessible when creating a Linode from a backup. You may add new user data now.' | ||
) | ||
).toBeVisible(); | ||
}); | ||
}); |
56 changes: 56 additions & 0 deletions
56
packages/manager/src/features/Linodes/LinodeCreatev2/UserData/UserDataHeading.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import React from 'react'; | ||
|
||
import { Link } from 'src/components/Link'; | ||
import { Notice } from 'src/components/Notice/Notice'; | ||
import { Stack } from 'src/components/Stack'; | ||
import { TooltipIcon } from 'src/components/TooltipIcon'; | ||
import { Typography } from 'src/components/Typography'; | ||
|
||
import { useLinodeCreateQueryParams } from '../utilities'; | ||
|
||
import type { LinodeCreateType } from '../../LinodesCreate/types'; | ||
|
||
export const UserDataHeading = () => { | ||
const { params } = useLinodeCreateQueryParams(); | ||
|
||
const warningMessageMap: Record<LinodeCreateType, null | string> = { | ||
Backups: | ||
'Existing user data is not accessible when creating a Linode from a backup. You may add new user data now.', | ||
'Clone Linode': | ||
'Existing user data is not cloned. You may add new user data now.', | ||
Distributions: null, | ||
Images: null, | ||
'One-Click': null, | ||
StackScripts: null, | ||
}; | ||
|
||
const warningMessage = params.type ? warningMessageMap[params.type] : null; | ||
|
||
return ( | ||
<Stack spacing={1}> | ||
<Stack direction="row" spacing={1}> | ||
<Typography variant="h2">Add User Data</Typography> | ||
<TooltipIcon | ||
text={ | ||
<> | ||
User data allows you to provide additional custom data to | ||
cloud-init to further configure your system.{' '} | ||
<Link to="https://www.linode.com/docs/products/compute/compute-instances/guides/metadata/"> | ||
Learn more | ||
</Link> | ||
. | ||
</> | ||
} | ||
interactive | ||
status="help" | ||
sxTooltipIcon={{ p: 0 }} | ||
/> | ||
</Stack> | ||
{warningMessage && ( | ||
<Notice spacingBottom={0} spacingTop={0} variant="warning"> | ||
{warningMessage} | ||
</Notice> | ||
)} | ||
</Stack> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.