import { FormEventHandler, useEffect, useState, VFC } from 'react'; import { useSearchParams } from 'react-router-dom'; import { Box, Paper, useTheme } from '@mui/material'; import { PageContent } from 'component/common/PageContent/PageContent'; import { PageHeader } from 'component/common/PageHeader/PageHeader'; import useToast from 'hooks/useToast'; import { formatUnknownError } from 'utils/formatUnknownError'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { usePlaygroundApi } from 'hooks/api/actions/usePlayground/usePlayground'; import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments'; import { PlaygroundForm } from './PlaygroundForm/PlaygroundForm'; import { resolveDefaultEnvironment, resolveEnvironments, resolveProjects, resolveResultsWidth, } from './playground.utils'; import { PlaygroundGuidance } from './PlaygroundGuidance/PlaygroundGuidance'; import { PlaygroundGuidancePopper } from './PlaygroundGuidancePopper/PlaygroundGuidancePopper'; import Loader from '../../common/Loader/Loader'; import { AdvancedPlaygroundResultsTable } from './AdvancedPlaygroundResultsTable/AdvancedPlaygroundResultsTable'; import { AdvancedPlaygroundResponseSchema } from 'openapi'; import { createLocalStorage } from 'utils/createLocalStorage'; export const AdvancedPlayground: VFC<{ FormComponent?: typeof PlaygroundForm; }> = ({ FormComponent = PlaygroundForm }) => { const defaultSettings: { projects: string[]; environments: string[]; context?: string; } = { projects: [], environments: [] }; const { value, setValue } = createLocalStorage( 'AdvancedPlayground:v1', defaultSettings ); const { environments: availableEnvironments } = useEnvironments(); const theme = useTheme(); const matches = true; const [environments, setEnvironments] = useState( value.environments ); const [projects, setProjects] = useState(value.projects); const [context, setContext] = useState(value.context); const [results, setResults] = useState< AdvancedPlaygroundResponseSchema | undefined >(); const { setToastData } = useToast(); const [searchParams, setSearchParams] = useSearchParams(); const searchParamsLength = Array.from(searchParams.entries()).length; const { evaluateAdvancedPlayground, loading } = usePlaygroundApi(); useEffect(() => { if (environments.length === 0) { setEnvironments([resolveDefaultEnvironment(availableEnvironments)]); } }, [availableEnvironments]); useEffect(() => { if (searchParamsLength > 0) { loadInitialValuesFromUrl(); } }, []); const loadInitialValuesFromUrl = () => { try { const environments = resolveEnvironmentsFromUrl(); const projects = resolveProjectsFromUrl(); const context = resolveContextFromUrl(); const makePlaygroundRequest = async () => { if (environments && context) { await evaluatePlaygroundContext( environments || [], projects || '*', context ); } }; makePlaygroundRequest(); } catch (error) { setToastData({ type: 'error', title: `Failed to parse URL parameters: ${formatUnknownError( error )}`, }); } }; const resolveEnvironmentsFromUrl = (): string[] | null => { let environmentArray: string[] | null = null; const environmentsFromUrl = searchParams.get('environments'); if (environmentsFromUrl) { environmentArray = environmentsFromUrl.split(','); setEnvironments(environmentArray); } return environmentArray; }; const resolveProjectsFromUrl = (): string[] | null => { let projectsArray: string[] | null = null; let projectsFromUrl = searchParams.get('projects'); if (projectsFromUrl) { projectsArray = projectsFromUrl.split(','); setProjects(projectsArray); } return projectsArray; }; const resolveContextFromUrl = () => { let contextFromUrl = searchParams.get('context'); if (contextFromUrl) { contextFromUrl = decodeURI(contextFromUrl); setContext(contextFromUrl); } return contextFromUrl; }; const evaluatePlaygroundContext = async ( environments: string[] | string, projects: string[] | string, context: string | undefined, action?: () => void ) => { try { const parsedContext = JSON.parse(context || '{}'); const response = await evaluateAdvancedPlayground({ environments: resolveEnvironments(environments), projects: resolveProjects(projects), context: { appName: 'playground', ...parsedContext, }, }); if (action && typeof action === 'function') { action(); } setResults(response); } catch (error: unknown) { setToastData({ type: 'error', title: `Error parsing context: ${formatUnknownError(error)}`, }); } }; const onSubmit: FormEventHandler = async event => { event.preventDefault(); await evaluatePlaygroundContext(environments, projects, context, () => { setURLParameters(); setValue({ environments, projects, context, }); }); }; const setURLParameters = () => { searchParams.set('context', encodeURI(context || '')); // always set because of native validation if ( Array.isArray(environments) && environments.length > 0 && !(environments.length === 1 && environments[0] === '*') ) { searchParams.set('environments', environments.join(',')); } else { searchParams.delete('projects'); } if ( Array.isArray(projects) && projects.length > 0 && !(projects.length === 1 && projects[0] === '*') ) { searchParams.set('projects', projects.join(',')); } else { searchParams.delete('projects'); } setSearchParams(searchParams); }; const formWidth = results && !matches ? '35%' : 'auto'; const resultsWidth = resolveResultsWidth(matches, results); return ( } /> } disableLoading bodyClass={'no-padding'} > ({ width: resultsWidth, transition: 'width 0.4s ease', padding: theme.spacing(4, 2), })} > } elseShow={ } elseShow={} /> } /> ); }; export default AdvancedPlayground;