1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-10-18 20:09:08 +02:00
unleash.unleash/frontend/src/component/playground/Playground/Playground.tsx
andreas-unleash a4c6ae2077 Added unknown evaluation state to table
Moved playground.model.ts to Playground folder
2022-08-09 17:41:43 +03:00

218 lines
7.7 KiB
TypeScript

import { FormEventHandler, useEffect, useState, VFC } from 'react';
import { useSearchParams } from 'react-router-dom';
import { Box, Paper, useMediaQuery, 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 { PlaygroundResultsTable } from './PlaygroundResultsTable/PlaygroundResultsTable';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { usePlaygroundApi } from 'hooks/api/actions/usePlayground/usePlayground';
import { PlaygroundResponseSchema } from 'component/playground/Playground/interfaces/playground.model';
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
import { PlaygroundForm } from './PlaygroundForm/PlaygroundForm';
import {
resolveDefaultEnvironment,
resolveProjects,
resolveResultsWidth,
} from './playground.utils';
import { PlaygroundGuidance } from './PlaygroundGuidance/PlaygroundGuidance';
import { PlaygroundGuidancePopper } from './PlaygroundGuidancePopper/PlaygroundGuidancePopper';
export const Playground: VFC<{}> = () => {
const { environments } = useEnvironments();
const theme = useTheme();
const matches = useMediaQuery(theme.breakpoints.down('lg'));
const [environment, setEnvironment] = useState<string>('');
const [projects, setProjects] = useState<string[]>([]);
const [context, setContext] = useState<string>();
const [results, setResults] = useState<
PlaygroundResponseSchema | undefined
>();
const { setToastData } = useToast();
const [searchParams, setSearchParams] = useSearchParams();
const { evaluatePlayground, loading } = usePlaygroundApi();
useEffect(() => {
setEnvironment(resolveDefaultEnvironment(environments));
}, [environments]);
useEffect(() => {
// Load initial values from URL
try {
const environmentFromUrl = searchParams.get('environment');
if (environmentFromUrl) {
setEnvironment(environmentFromUrl);
}
let projectsArray: string[];
let projectsFromUrl = searchParams.get('projects');
if (projectsFromUrl) {
projectsArray = projectsFromUrl.split(',');
setProjects(projectsArray);
}
let contextFromUrl = searchParams.get('context');
if (contextFromUrl) {
contextFromUrl = decodeURI(contextFromUrl);
setContext(contextFromUrl);
}
const makePlaygroundRequest = async () => {
if (environmentFromUrl && contextFromUrl) {
await evaluatePlaygroundContext(
environmentFromUrl,
projectsArray || '*',
contextFromUrl
);
}
};
makePlaygroundRequest();
} catch (error) {
setToastData({
type: 'error',
title: `Failed to parse URL parameters: ${formatUnknownError(
error
)}`,
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const evaluatePlaygroundContext = async (
environment: string,
projects: string[] | string,
context: string | undefined,
action?: () => void
) => {
try {
const parsedContext = JSON.parse(context || '{}');
const response = await evaluatePlayground({
environment,
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<HTMLFormElement> = async event => {
event.preventDefault();
await evaluatePlaygroundContext(
environment,
projects,
context,
setURLParameters
);
};
const setURLParameters = () => {
searchParams.set('context', encodeURI(context || '')); // always set because of native validation
searchParams.set('environment', environment);
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 (
<PageContent
header={
<PageHeader
title="Unleash playground"
actions={<PlaygroundGuidancePopper />}
/>
}
disableLoading
bodyClass={'no-padding'}
>
<Box
sx={{
display: 'flex',
flexDirection: !matches ? 'row' : 'column',
}}
>
<Box
sx={{
background: theme.palette.grey[200],
borderBottomLeftRadius: theme.shape.borderRadiusMedium,
}}
>
<Paper
elevation={0}
sx={{
px: 4,
py: 3,
mb: 4,
mt: 2,
background: theme.palette.grey[200],
transition: 'width 0.4s ease',
minWidth: matches ? 'auto' : '500px',
width: formWidth,
position: 'sticky',
top: 0,
}}
>
<PlaygroundForm
onSubmit={onSubmit}
context={context}
setContext={setContext}
environments={environments}
projects={projects}
environment={environment}
setProjects={setProjects}
setEnvironment={setEnvironment}
/>
</Paper>
</Box>
<Box
sx={theme => ({
width: resultsWidth,
transition: 'width 0.4s ease',
padding: theme.spacing(4, 2),
})}
>
<ConditionallyRender
condition={Boolean(results)}
show={
<PlaygroundResultsTable
loading={loading}
features={results?.features}
input={results?.input}
/>
}
elseShow={<PlaygroundGuidance />}
/>
</Box>
</Box>
</PageContent>
);
};
export default Playground;