mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Playground fields with Change request (#7724)
using `changeRequest` value from URL
This commit is contained in:
		
							parent
							
								
									65131727c1
								
							
						
					
					
						commit
						4b6813aa5e
					
				| @ -1,4 +1,4 @@ | ||||
| import { type FormEventHandler, useEffect, useState, type VFC } from 'react'; | ||||
| import { type FormEventHandler, useEffect, useState, type FC } from 'react'; | ||||
| import { useSearchParams } from 'react-router-dom'; | ||||
| import { Box, Paper, useTheme, styled, Alert } from '@mui/material'; | ||||
| import { PageContent } from 'component/common/PageContent/PageContent'; | ||||
| @ -81,7 +81,7 @@ const GenerateWarningMessages: React.FC<{ | ||||
|     } | ||||
| }; | ||||
| 
 | ||||
| export const AdvancedPlayground: VFC<{ | ||||
| export const AdvancedPlayground: FC<{ | ||||
|     FormComponent?: typeof PlaygroundForm; | ||||
| }> = ({ FormComponent = PlaygroundForm }) => { | ||||
|     const defaultSettings: { | ||||
| @ -112,7 +112,7 @@ export const AdvancedPlayground: VFC<{ | ||||
|     >(); | ||||
|     const { setToastData } = useToast(); | ||||
|     const [searchParams, setSearchParams] = useSearchParams(); | ||||
|     const searchParamsLength = Array.from(searchParams.entries()).length; | ||||
|     const [changeRequest, setChangeRequest] = useState<string>(); | ||||
|     const { evaluateAdvancedPlayground, loading, errors } = usePlaygroundApi(); | ||||
|     const [hasFormBeenSubmitted, setHasFormBeenSubmitted] = useState(false); | ||||
| 
 | ||||
| @ -123,28 +123,25 @@ export const AdvancedPlayground: VFC<{ | ||||
|     }, [JSON.stringify(environments), JSON.stringify(availableEnvironments)]); | ||||
| 
 | ||||
|     useEffect(() => { | ||||
|         if (searchParamsLength > 0) { | ||||
|             loadInitialValuesFromUrl(); | ||||
|         } | ||||
|         loadInitialValuesFromUrl(); | ||||
|     }, []); | ||||
| 
 | ||||
|     const loadInitialValuesFromUrl = () => { | ||||
|     const loadInitialValuesFromUrl = async () => { | ||||
|         try { | ||||
|             const environments = resolveEnvironmentsFromUrl(); | ||||
|             const projects = resolveProjectsFromUrl(); | ||||
|             const context = resolveContextFromUrl(); | ||||
|             const token = resolveTokenFromUrl(); | ||||
|             const makePlaygroundRequest = async () => { | ||||
|                 if (environments && context) { | ||||
|                     await evaluatePlaygroundContext( | ||||
|                         environments || [], | ||||
|                         projects || '*', | ||||
|                         context, | ||||
|                     ); | ||||
|                 } | ||||
|             }; | ||||
|             resolveTokenFromUrl(); | ||||
|             resolveChangeRequestFromUrl(); | ||||
|             // TODO: Add support for changeRequest
 | ||||
| 
 | ||||
|             makePlaygroundRequest(); | ||||
|             if (environments && context) { | ||||
|                 await evaluatePlaygroundContext( | ||||
|                     environments || [], | ||||
|                     projects || '*', | ||||
|                     context, | ||||
|                 ); | ||||
|             } | ||||
|         } catch (error) { | ||||
|             setToastData({ | ||||
|                 type: 'error', | ||||
| @ -191,6 +188,13 @@ export const AdvancedPlayground: VFC<{ | ||||
|         return tokenFromUrl; | ||||
|     }; | ||||
| 
 | ||||
|     const resolveChangeRequestFromUrl = () => { | ||||
|         const changeRequestFromUrl = searchParams.get('changeRequest'); | ||||
|         if (changeRequestFromUrl) { | ||||
|             setChangeRequest(changeRequestFromUrl); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     const evaluatePlaygroundContext = async ( | ||||
|         environments: string[] | string, | ||||
|         projects: string[] | string, | ||||
| @ -243,14 +247,20 @@ export const AdvancedPlayground: VFC<{ | ||||
| 
 | ||||
|         await evaluatePlaygroundContext(environments, projects, context, () => { | ||||
|             setURLParameters(); | ||||
|             setValue({ | ||||
|                 environments, | ||||
|                 projects, | ||||
|                 context, | ||||
|             }); | ||||
|             if (!changeRequest) { | ||||
|                 setValue({ | ||||
|                     environments, | ||||
|                     projects, | ||||
|                     context, | ||||
|                 }); | ||||
|             } | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     const onClearChangeRequest = () => { | ||||
|         setChangeRequest(undefined); | ||||
|     }; | ||||
| 
 | ||||
|     const setURLParameters = () => { | ||||
|         searchParams.set('context', encodeURI(context || '')); // always set because of native validation
 | ||||
|         if ( | ||||
| @ -271,6 +281,11 @@ export const AdvancedPlayground: VFC<{ | ||||
|         } else { | ||||
|             searchParams.delete('projects'); | ||||
|         } | ||||
|         if (changeRequest) { | ||||
|             searchParams.set('changeRequest', changeRequest); | ||||
|         } else { | ||||
|             searchParams.delete('changeRequest'); | ||||
|         } | ||||
|         setSearchParams(searchParams); | ||||
|     }; | ||||
| 
 | ||||
| @ -326,6 +341,8 @@ export const AdvancedPlayground: VFC<{ | ||||
|                             setToken={setToken} | ||||
|                             setProjects={setProjects} | ||||
|                             setEnvironments={setEnvironments} | ||||
|                             changeRequest={changeRequest || undefined} | ||||
|                             onClearChangeRequest={onClearChangeRequest} | ||||
|                         /> | ||||
|                     </Paper> | ||||
|                 </Box> | ||||
|  | ||||
| @ -0,0 +1,71 @@ | ||||
| import type { ComponentProps, Dispatch, FC, SetStateAction } from 'react'; | ||||
| import { Autocomplete, TextField } from '@mui/material'; | ||||
| import { renderOption } from '../../renderOption'; | ||||
| 
 | ||||
| interface IEnvironmentsFieldProps { | ||||
|     environments: string[]; | ||||
|     setEnvironments: Dispatch<SetStateAction<string[]>>; | ||||
|     availableEnvironments: string[]; | ||||
|     disabled?: boolean; | ||||
| } | ||||
| 
 | ||||
| interface IOption { | ||||
|     label: string; | ||||
|     id: string; | ||||
| } | ||||
| 
 | ||||
| export const EnvironmentsField: FC<IEnvironmentsFieldProps> = ({ | ||||
|     environments, | ||||
|     setEnvironments, | ||||
|     availableEnvironments, | ||||
|     disabled, | ||||
| }) => { | ||||
|     const environmentOptions = [ | ||||
|         ...availableEnvironments.map((name) => ({ | ||||
|             label: name, | ||||
|             id: name, | ||||
|         })), | ||||
|     ]; | ||||
|     const envValue = environmentOptions.filter(({ id }) => | ||||
|         environments.includes(id), | ||||
|     ); | ||||
| 
 | ||||
|     const onEnvironmentsChange: ComponentProps< | ||||
|         typeof Autocomplete | ||||
|     >['onChange'] = (event, value, reason) => { | ||||
|         const newEnvironments = value as IOption | IOption[]; | ||||
|         if (reason === 'clear' || newEnvironments === null) { | ||||
|             return setEnvironments([]); | ||||
|         } | ||||
|         if (Array.isArray(newEnvironments)) { | ||||
|             if (newEnvironments.length === 0) { | ||||
|                 return setEnvironments([]); | ||||
|             } | ||||
|             return setEnvironments(newEnvironments.map(({ id }) => id)); | ||||
|         } | ||||
| 
 | ||||
|         return setEnvironments([newEnvironments.id]); | ||||
|     }; | ||||
| 
 | ||||
|     return ( | ||||
|         <Autocomplete | ||||
|             disablePortal | ||||
|             limitTags={3} | ||||
|             id='environment' | ||||
|             multiple={true} | ||||
|             options={environmentOptions} | ||||
|             sx={{ flex: 1 }} | ||||
|             renderInput={(params) => ( | ||||
|                 <TextField {...params} label='Environments' /> | ||||
|             )} | ||||
|             renderOption={renderOption} | ||||
|             getOptionLabel={({ label }) => label} | ||||
|             disableCloseOnSelect={false} | ||||
|             size='small' | ||||
|             value={envValue} | ||||
|             onChange={onEnvironmentsChange} | ||||
|             disabled={disabled} | ||||
|             data-testid={'PLAYGROUND_ENVIRONMENT_SELECT'} | ||||
|         /> | ||||
|     ); | ||||
| }; | ||||
| @ -3,6 +3,7 @@ import { render } from 'utils/testRenderer'; | ||||
| import { fireEvent, screen, within } from '@testing-library/react'; | ||||
| import { PlaygroundConnectionFieldset } from './PlaygroundConnectionFieldset'; | ||||
| import { useState } from 'react'; | ||||
| import userEvent from '@testing-library/user-event'; | ||||
| 
 | ||||
| const server = testServerSetup(); | ||||
| 
 | ||||
| @ -11,6 +12,9 @@ beforeEach(() => { | ||||
|         versionInfo: { | ||||
|             current: { oss: 'version', enterprise: 'version' }, | ||||
|         }, | ||||
|         flags: { | ||||
|             changeRequestPlayground: true, | ||||
|         }, | ||||
|     }); | ||||
|     testServerRoute( | ||||
|         server, | ||||
| @ -203,3 +207,43 @@ test('should have a working clear button when token is filled', async () => { | ||||
| 
 | ||||
|     expect(tokenInput).toHaveValue(''); | ||||
| }); | ||||
| 
 | ||||
| test('should show change request and disable other fields until removed', async () => { | ||||
|     const Component = () => { | ||||
|         const [environments, setEnvironments] = useState<string[]>([]); | ||||
|         const [projects, setProjects] = useState<string[]>(['test-project']); | ||||
|         const [token, setToken] = useState<string>(); | ||||
|         const [changeRequest, setChangeRequest] = useState('CR #1'); | ||||
| 
 | ||||
|         const availableEnvironments = ['development', 'production']; | ||||
| 
 | ||||
|         return ( | ||||
|             <PlaygroundConnectionFieldset | ||||
|                 environments={environments} | ||||
|                 projects={projects} | ||||
|                 token={token} | ||||
|                 setToken={setToken} | ||||
|                 setEnvironments={setEnvironments} | ||||
|                 setProjects={setProjects} | ||||
|                 availableEnvironments={availableEnvironments} | ||||
|                 changeRequest={changeRequest} | ||||
|                 onClearChangeRequest={() => setChangeRequest('')} | ||||
|             /> | ||||
|         ); | ||||
|     }; | ||||
|     render(<Component />); | ||||
| 
 | ||||
|     const changeRequestInput = await screen.findByDisplayValue('CR #1'); | ||||
|     // expect(changeRequestInput).toHaveValue('CR #1');
 | ||||
|     const viewButton = await screen.findByText(/View change request/); | ||||
|     expect(viewButton).toHaveProperty( | ||||
|         'href', | ||||
|         'http://localhost:3000/projects/test-project/change-requests/CR%20#1', | ||||
|     ); | ||||
|     // TODO: check if other fields are disabled
 | ||||
| 
 | ||||
|     const clearButton = await screen.findByLabelText(/clear change request/i); | ||||
| 
 | ||||
|     await userEvent.click(clearButton); | ||||
|     expect(changeRequestInput).not.toBeInTheDocument(); | ||||
| }); | ||||
|  | ||||
| @ -3,22 +3,20 @@ import { | ||||
|     type Dispatch, | ||||
|     type SetStateAction, | ||||
|     useState, | ||||
|     type VFC, | ||||
|     type FC, | ||||
| } from 'react'; | ||||
| import { | ||||
|     Autocomplete, | ||||
|     Box, | ||||
|     Button, | ||||
|     IconButton, | ||||
|     InputAdornment, | ||||
|     styled, | ||||
|     TextField, | ||||
|     type TextField, | ||||
|     Tooltip, | ||||
|     Typography, | ||||
|     useTheme, | ||||
| } from '@mui/material'; | ||||
| import useProjects from 'hooks/api/getters/useProjects/useProjects'; | ||||
| import { renderOption } from '../renderOption'; | ||||
| import { | ||||
|     type IApiToken, | ||||
|     useApiTokens, | ||||
| @ -32,6 +30,8 @@ import Clear from '@mui/icons-material/Clear'; | ||||
| import { ProjectSelect } from '../../../../common/ProjectSelect/ProjectSelect'; | ||||
| import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; | ||||
| import { useUiFlag } from 'hooks/useUiFlag'; | ||||
| import { EnvironmentsField } from './EnvironmentsField/EnvironmentsField'; | ||||
| import { Link } from 'react-router-dom'; | ||||
| 
 | ||||
| interface IPlaygroundConnectionFieldsetProps { | ||||
|     environments: string[]; | ||||
| @ -41,6 +41,8 @@ interface IPlaygroundConnectionFieldsetProps { | ||||
|     setEnvironments: Dispatch<SetStateAction<string[]>>; | ||||
|     setToken?: Dispatch<SetStateAction<string | undefined>>; | ||||
|     availableEnvironments: string[]; | ||||
|     changeRequest?: string; | ||||
|     onClearChangeRequest?: () => void; | ||||
| } | ||||
| 
 | ||||
| interface IOption { | ||||
| @ -61,7 +63,7 @@ const StyledInput = styled(Input)(() => ({ | ||||
| const StyledGrid = styled(Box)(({ theme }) => ({ | ||||
|     display: 'grid', | ||||
|     columnGap: theme.spacing(2), | ||||
|     rowGap: theme.spacing(4), | ||||
|     rowGap: theme.spacing(2), | ||||
|     gridTemplateColumns: '1fr', | ||||
| 
 | ||||
|     [theme.breakpoints.up('md')]: { | ||||
| @ -69,7 +71,16 @@ const StyledGrid = styled(Box)(({ theme }) => ({ | ||||
|     }, | ||||
| })); | ||||
| 
 | ||||
| export const PlaygroundConnectionFieldset: VFC< | ||||
| const StyledChangeRequestInput = styled(StyledInput)(({ theme }) => ({ | ||||
|     '& label': { | ||||
|         WebkitTextFillColor: theme.palette.text.secondary, | ||||
|     }, | ||||
|     '& input.Mui-disabled': { | ||||
|         WebkitTextFillColor: theme.palette.text.secondary, | ||||
|     }, | ||||
| })); | ||||
| 
 | ||||
| export const PlaygroundConnectionFieldset: FC< | ||||
|     IPlaygroundConnectionFieldsetProps | ||||
| > = ({ | ||||
|     environments, | ||||
| @ -79,6 +90,8 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
|     setEnvironments, | ||||
|     setToken, | ||||
|     availableEnvironments, | ||||
|     changeRequest, | ||||
|     onClearChangeRequest, | ||||
| }) => { | ||||
|     const theme = useTheme(); | ||||
|     const { tokens } = useApiTokens(); | ||||
| @ -86,9 +99,7 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
| 
 | ||||
|     const { projects: availableProjects } = useProjects(); | ||||
| 
 | ||||
|     const isChangeRequestPlaygroundEnabled = useUiFlag( | ||||
|         'changeRequestPlayground', | ||||
|     ); | ||||
|     const changeRequestPlaygroundEnabled = useUiFlag('changeRequestPlayground'); | ||||
| 
 | ||||
|     const projectsOptions = [ | ||||
|         allOption, | ||||
| @ -97,35 +108,6 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
|             id, | ||||
|         })), | ||||
|     ]; | ||||
| 
 | ||||
|     const environmentOptions = [ | ||||
|         ...availableEnvironments.map((name) => ({ | ||||
|             label: name, | ||||
|             id: name, | ||||
|         })), | ||||
|     ]; | ||||
| 
 | ||||
|     const onEnvironmentsChange: ComponentProps< | ||||
|         typeof Autocomplete | ||||
|     >['onChange'] = (event, value, reason) => { | ||||
|         const newEnvironments = value as IOption | IOption[]; | ||||
|         if (reason === 'clear' || newEnvironments === null) { | ||||
|             return setEnvironments([]); | ||||
|         } | ||||
|         if (Array.isArray(newEnvironments)) { | ||||
|             if (newEnvironments.length === 0) { | ||||
|                 return setEnvironments([]); | ||||
|             } | ||||
|             return setEnvironments(newEnvironments.map(({ id }) => id)); | ||||
|         } | ||||
| 
 | ||||
|         return setEnvironments([newEnvironments.id]); | ||||
|     }; | ||||
| 
 | ||||
|     const envValue = environmentOptions.filter(({ id }) => | ||||
|         environments.includes(id), | ||||
|     ); | ||||
| 
 | ||||
|     const onSetToken: ComponentProps<typeof TextField>['onChange'] = async ( | ||||
|         event, | ||||
|     ) => { | ||||
| @ -208,18 +190,6 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
|         resetTokenState(); | ||||
|     }; | ||||
| 
 | ||||
|     const renderClearButton = () => ( | ||||
|         <InputAdornment position='end' data-testid='TOKEN_INPUT_CLEAR_BTN'> | ||||
|             <IconButton | ||||
|                 aria-label='toggle password visibility' | ||||
|                 onClick={clearToken} | ||||
|                 edge='end' | ||||
|             > | ||||
|                 <SmallClear /> | ||||
|             </IconButton> | ||||
|         </InputAdornment> | ||||
|     ); | ||||
| 
 | ||||
|     return ( | ||||
|         <Box sx={{ pb: 2 }}> | ||||
|             <Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}> | ||||
| @ -241,25 +211,14 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
|                                 : 'Select environments to use in the playground' | ||||
|                         } | ||||
|                     > | ||||
|                         <Autocomplete | ||||
|                             disablePortal | ||||
|                             limitTags={3} | ||||
|                             id='environment' | ||||
|                             multiple={true} | ||||
|                             options={environmentOptions} | ||||
|                             sx={{ flex: 1 }} | ||||
|                             renderInput={(params) => ( | ||||
|                                 <TextField {...params} label='Environments' /> | ||||
|                             )} | ||||
|                             renderOption={renderOption} | ||||
|                             getOptionLabel={({ label }) => label} | ||||
|                             disableCloseOnSelect={false} | ||||
|                             size='small' | ||||
|                             value={envValue} | ||||
|                             onChange={onEnvironmentsChange} | ||||
|                             disabled={Boolean(token)} | ||||
|                             data-testid={'PLAYGROUND_ENVIRONMENT_SELECT'} | ||||
|                         /> | ||||
|                         <Box> | ||||
|                             <EnvironmentsField | ||||
|                                 environments={environments} | ||||
|                                 setEnvironments={setEnvironments} | ||||
|                                 availableEnvironments={availableEnvironments} | ||||
|                                 disabled={Boolean(token || changeRequest)} | ||||
|                             /> | ||||
|                         </Box> | ||||
|                     </Tooltip> | ||||
|                 </Box> | ||||
|                 <Box> | ||||
| @ -275,7 +234,7 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
|                             selectedProjects={projects} | ||||
|                             onChange={setProjects} | ||||
|                             dataTestId={'PLAYGROUND_PROJECT_SELECT'} | ||||
|                             disabled={Boolean(token)} | ||||
|                             disabled={Boolean(token || changeRequest)} | ||||
|                             limitTags={3} | ||||
|                         /> | ||||
|                     </Tooltip> | ||||
| @ -283,7 +242,7 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
|                 <Box> | ||||
|                     <StyledInput | ||||
|                         label='API token' | ||||
|                         value={token || ''} | ||||
|                         value={token || changeRequest ? ' ' : ''} | ||||
|                         onChange={onSetToken} | ||||
|                         type={'text'} | ||||
|                         error={Boolean(tokenError)} | ||||
| @ -291,36 +250,67 @@ export const PlaygroundConnectionFieldset: VFC< | ||||
|                         placeholder={'Enter your API token'} | ||||
|                         data-testid={'PLAYGROUND_TOKEN_INPUT'} | ||||
|                         InputProps={{ | ||||
|                             endAdornment: token ? renderClearButton() : null, | ||||
|                             endAdornment: token ? ( | ||||
|                                 <InputAdornment | ||||
|                                     position='end' | ||||
|                                     data-testid='TOKEN_INPUT_CLEAR_BTN' | ||||
|                                 > | ||||
|                                     <IconButton | ||||
|                                         aria-label='clear API token' | ||||
|                                         onClick={clearToken} | ||||
|                                         edge='end' | ||||
|                                     > | ||||
|                                         <SmallClear /> | ||||
|                                     </IconButton> | ||||
|                                 </InputAdornment> | ||||
|                             ) : null, | ||||
|                         }} | ||||
|                         disabled={Boolean(changeRequest)} | ||||
|                     /> | ||||
|                 </Box> | ||||
|                 <ConditionallyRender | ||||
|                     condition={Boolean(isChangeRequestPlaygroundEnabled)} | ||||
|                     condition={Boolean( | ||||
|                         changeRequestPlaygroundEnabled && changeRequest, | ||||
|                     )} | ||||
|                     show={ | ||||
|                         <Box sx={{ display: 'flex', gap: 2 }}> | ||||
|                             <Box sx={{ flex: 1 }}> | ||||
|                                 <StyledInput | ||||
|                                 <StyledChangeRequestInput | ||||
|                                     label='Change request' | ||||
|                                     value={ | ||||
|                                         '// TODO: Change request #5 (feature1, feature2)' | ||||
|                                     } | ||||
|                                     value={changeRequest || ''} | ||||
|                                     onChange={() => {}} | ||||
|                                     type={'text'} | ||||
|                                     // error={Boolean(tokenError)}
 | ||||
|                                     // errorText={tokenError}
 | ||||
|                                     // error={Boolean(changeRequestError)}
 | ||||
|                                     // errorText={changeRequestError)}}
 | ||||
|                                     placeholder={'Enter your API token'} | ||||
|                                     data-testid={'PLAYGROUND_TOKEN_INPUT'} | ||||
|                                     // disabled
 | ||||
|                                     disabled | ||||
|                                     InputProps={{ | ||||
|                                         endAdornment: renderClearButton(), | ||||
|                                         sx: { | ||||
|                                             cursor: 'default', | ||||
|                                         }, | ||||
|                                         endAdornment: ( | ||||
|                                             <InputAdornment | ||||
|                                                 position='end' | ||||
|                                                 data-testid='CR_INPUT_CLEAR_BTN' | ||||
|                                             > | ||||
|                                                 <IconButton | ||||
|                                                     aria-label='clear Change request results' | ||||
|                                                     onClick={ | ||||
|                                                         onClearChangeRequest | ||||
|                                                     } | ||||
|                                                     edge='end' | ||||
|                                                 > | ||||
|                                                     <SmallClear /> | ||||
|                                                 </IconButton> | ||||
|                                             </InputAdornment> | ||||
|                                         ), | ||||
|                                     }} | ||||
|                                 /> | ||||
|                             </Box> | ||||
|                             <Button variant='outlined' size='small'> | ||||
|                             <Button | ||||
|                                 variant='outlined' | ||||
|                                 size='small' | ||||
|                                 to={`/projects/${projects[0]}/change-requests/${changeRequest}`} | ||||
|                                 component={Link} | ||||
|                             > | ||||
|                                 View change request | ||||
|                             </Button> | ||||
|                         </Box> | ||||
|  | ||||
| @ -15,6 +15,8 @@ interface IPlaygroundFormProps { | ||||
|     setEnvironments: React.Dispatch<React.SetStateAction<string[]>>; | ||||
|     context: string | undefined; | ||||
|     setContext: React.Dispatch<React.SetStateAction<string | undefined>>; | ||||
|     changeRequest?: string; | ||||
|     onClearChangeRequest?: () => void; | ||||
| } | ||||
| 
 | ||||
| export const PlaygroundForm: VFC<IPlaygroundFormProps> = ({ | ||||
| @ -28,6 +30,8 @@ export const PlaygroundForm: VFC<IPlaygroundFormProps> = ({ | ||||
|     setEnvironments, | ||||
|     context, | ||||
|     setContext, | ||||
|     changeRequest, | ||||
|     onClearChangeRequest, | ||||
| }) => { | ||||
|     return ( | ||||
|         <Box | ||||
| @ -50,6 +54,8 @@ export const PlaygroundForm: VFC<IPlaygroundFormProps> = ({ | ||||
|                 availableEnvironments={availableEnvironments.map( | ||||
|                     ({ name }) => name, | ||||
|                 )} | ||||
|                 changeRequest={changeRequest} | ||||
|                 onClearChangeRequest={onClearChangeRequest} | ||||
|             /> | ||||
| 
 | ||||
|             <PlaygroundCodeFieldset context={context} setContext={setContext} /> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user