Compare commits

..

7 Commits

12 changed files with 325 additions and 215 deletions

2
.env
View File

@ -2,4 +2,4 @@ REACT_APP_KC_URL=https://auth-dev.csi.wmi.amu.edu.pl/
REACT_APP_KC_REALM=gonito-dev
REACT_APP_KC_CLIENT_ID=gonito-dev-localhost
REACT_APP_API=https://gonito.net/api
REACT_APP_API=https://gonito-back-dev.csi.wmi.amu.edu.pl/api

View File

@ -116,7 +116,12 @@ const App = () => {
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/howto`}
element={<Challenge section={2} />}
element={
<Challenge
popUpMessageHandler={popUpMessageHandler}
section={2}
/>
}
/>
<Route
path={`${CHALLENGE_PAGE}/:challengeId/myentries`}

View File

@ -1,30 +1,38 @@
import KeyCloakService from '../services/KeyCloakService';
import {API} from '../utils/globals';
import { API } from '../utils/globals';
const challengeSubmission = (challengeName, repoUrl, repoBranch, description, setLoading) => {
const details = {
'f1': description,
'f3': repoUrl,
'f4': repoBranch
};
let formBody = [];
for (let property in details) {
let encodedKey = encodeURIComponent(property);
let encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + '=' + encodedValue);
}
formBody = formBody.join('&');
fetch(`${API}/challenge-submission/${challengeName}`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'Authorization': `Bearer ${KeyCloakService.getToken()}`
},
body: formBody
}).then((resp) => resp.json())
const challengeSubmission = (
challengeName,
repoUrl,
repoBranch,
description,
setLoading
) => {
const details = {
f1: description,
f3: repoUrl,
f4: repoBranch,
};
let formBody = [];
for (let property in details) {
let encodedKey = encodeURIComponent(property);
let encodedValue = encodeURIComponent(details[property]);
formBody.push(encodedKey + '=' + encodedValue);
}
formBody = formBody.join('&');
fetch(`${API}/challenge-submission/${challengeName}`, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
Authorization: `Bearer ${KeyCloakService.getToken()}`,
},
body: formBody,
})
.then((resp) => resp.json())
.then((data) => {
setLoading(true);
window.location.replace(`https://gonito.net/open-view-progress/${data}#form`);
setLoading(true);
const processUrl = API.replace('/api', '');
window.location.replace(`${processUrl}/open-view-progress/${data}#form`);
});
};

View File

@ -0,0 +1,16 @@
import {API} from '../utils/globals';
import KeyCloakService from '../services/KeyCloakService';
const getFullUser = (setDataState, setLoadingState) => {
fetch(`${API}/full-user-info`, {
headers: {'Authorization': `Bearer ${KeyCloakService.getToken()}`}
})
.then(response => response.json())
.then(data => {
setDataState(data);
if (setLoadingState)
setLoadingState(false);
});
};
export default getFullUser;

View File

@ -1,70 +1,78 @@
import React from 'react';
import {FlexColumn, FlexRow, Svg} from '../../utils/containers';
import {Body, H2, Medium} from '../../utils/fonts';
import { FlexColumn, FlexRow, Svg } from '../../utils/containers';
import { Body, H2, Medium } from '../../utils/fonts';
import Media from 'react-media';
import theme from '../../utils/theme';
import uamLogo from '../../assets/uam-logo.svg';
const Csi = () => {
const mobileRender = () => {
return (
<FlexColumn as='section' alignmentX='flex-start'>
<H2 as='h2' margin='0 0 24px 0'>
Artificial Intelligence Centre (CSI)
</H2>
<Body as='p' margin='0 0 16px 0'>
<Medium as='span' display='inline'>Gonito.net</Medium> belongs to the
<Medium as='span' display='inline'>&nbsp;Artificial Intelligence Centre (CSI)&nbsp;</Medium>
at Adam Mickiewicz University (UAM) which conducts research on the development of artificial
intelligence, carries out scientific and research and development projects, integrates the research
of scientists from various departments of Adam Mickiewicz University and outside it - from leading
scientific centers in Poland and abroad as well as those employed in business entities.
</Body>
<Medium as='p'>
CSI also cooperates with business entities in creating new solutions to be implemented in
enterprises.
</Medium>
</FlexColumn>
);
};
const desktopRender = () => {
return (
<FlexRow gap='46px'>
<FlexColumn as='section' alignmentX='flex-start' maxWidth='490px'>
<H2 as='h2' margin='0 0 48px 0'>
Artificial Intelligence Centre (CSI)
</H2>
<Body as='p' margin='0 0 24px 0'>
<Medium as='span' display='inline'>Gonito.net</Medium> belongs to the
<Medium as='span' display='inline'>&nbsp;Artificial Intelligence Centre (CSI)&nbsp;</Medium>
at Adam Mickiewicz University (UAM) which conducts research on the development of artificial
intelligence, carries out scientific and research and development projects, integrates the
research
of scientists from various departments of Adam Mickiewicz University and outside it - from
leading
scientific centers in Poland and abroad as well as those employed in business entities.
</Body>
<Medium as='p'>
CSI also cooperates with business entities in creating new solutions to be implemented in
enterprises.
</Medium>
</FlexColumn>
<Svg src={uamLogo} width='200px' height='242px' size='contain'/>
</FlexRow>
);
};
const mobileRender = () => {
return (
<>
<Media query={theme.mobile}>
{mobileRender()}
</Media>
<Media query={theme.desktop}>
{desktopRender()}
</Media>
</>
<FlexColumn as="section" alignmentX="flex-start">
<H2 as="h2" margin="0 0 24px 0">
Center for Artificial Intelligence (C4AI)
</H2>
<Body as="p" margin="0 0 16px 0">
<Medium as="span" display="inline">
Gonito.net
</Medium>{' '}
belongs to the
<Medium as="span" display="inline">
&nbsp;Center for Artificial Intelligence (C4AI)&nbsp;
</Medium>
at Adam Mickiewicz University (UAM) which conducts research on the
development of artificial intelligence, carries out scientific and
research and development projects, integrates the research of
scientists from various departments of Adam Mickiewicz University and
outside it - from leading scientific centers in Poland and abroad as
well as those employed in business entities.
</Body>
<Medium as="p">
C4AI also cooperates with business entities in creating new solutions
to be implemented in enterprises.
</Medium>
</FlexColumn>
);
};
const desktopRender = () => {
return (
<FlexRow gap="46px">
<FlexColumn as="section" alignmentX="flex-start" maxWidth="490px">
<H2 as="h2" margin="0 0 48px 0">
Center for Artificial Intelligence (C4AI)
</H2>
<Body as="p" margin="0 0 24px 0">
<Medium as="span" display="inline">
Gonito.net
</Medium>{' '}
belongs to the
<Medium as="span" display="inline">
&nbsp;Center for Artificial Intelligence (C4AI)&nbsp;
</Medium>
at Adam Mickiewicz University (UAM) which conducts research on the
development of artificial intelligence, carries out scientific and
research and development projects, integrates the research of
scientists from various departments of Adam Mickiewicz University
and outside it - from leading scientific centers in Poland and
abroad as well as those employed in business entities.
</Body>
<Medium as="p">
C4AI also cooperates with business entities in creating new
solutions to be implemented in enterprises.
</Medium>
</FlexColumn>
<Svg src={uamLogo} width="200px" height="242px" size="contain" />
</FlexRow>
);
};
return (
<>
<Media query={theme.mobile}>{mobileRender()}</Media>
<Media query={theme.desktop}>{desktopRender()}</Media>
</>
);
};
export default Csi;
export default Csi;

View File

@ -1,23 +1,23 @@
import React from 'react';
import {FlexColumn, Svg} from '../../utils/containers';
import { FlexColumn, Svg } from '../../utils/containers';
import styled from 'styled-components';
import theme from '../../utils/theme';
import copyIco from '../../assets/copy_ico.svg';
import checkIco from '../../assets/check_ico.svg';
import {Body, Code} from '../../utils/fonts';
import { Body, Code } from '../../utils/fonts';
const CodeShellStyle = styled(FlexColumn)`
position: relative;
padding: 24px 14px 14px;
gap: 8px;
background-color: ${({theme}) => theme.colors.dark07};
border: 1px solid ${({theme}) => theme.colors.dark};
background-color: ${({ theme }) => theme.colors.dark07};
border: 1px solid ${({ theme }) => theme.colors.dark};
border-radius: 4px;
width: 100%;
align-items: flex-start;
max-width: ${({maxWidth}) => maxWidth ? maxWidth : 'none'};
max-width: ${({ maxWidth }) => (maxWidth ? maxWidth : 'none')};
@media (min-width: ${({theme}) => theme.overMobile}) {
@media (min-width: ${({ theme }) => theme.overMobile}) {
gap: 12px;
padding: 40px 32px 32px;
}
@ -28,59 +28,63 @@ const CopiedMessageStyle = styled(Body)`
position: absolute;
top: -24px;
right: -10px;
background-color: ${({theme}) => theme.colors.green};
color: ${({theme}) => theme.colors.white};
background-color: ${({ theme }) => theme.colors.green};
color: ${({ theme }) => theme.colors.white};
border-radius: 4px;
padding: 6px;
`;
const CodeShell = (props) => {
const [ico, setIco] = React.useState(copyIco);
const [ico, setIco] = React.useState(copyIco);
const clickCopyButton = () => {
let commands = '';
if (props.commands.length > 1) {
for (let command of props.commands)
commands += command + '\n';
} else commands = props.commands;
navigator.clipboard.writeText(commands).then(r => console.log(r));
setIco(checkIco);
setTimeout(() => {
setIco(copyIco);
}, 3000);
};
const clickCopyButton = () => {
let commands = '';
if (props.commands.length > 1) {
for (let command of props.commands) commands += command + '\n';
} else commands = props.commands;
navigator.clipboard.writeText(commands).then((r) => console.log(r));
setIco(checkIco);
setTimeout(() => {
setIco(copyIco);
}, 2000);
};
const formatCommand = (command) => {
if (command[0] === '\t') {
return <>&nbsp;&nbsp;&nbsp;&nbsp;{formatCommand(command.slice(1))}</>;
/* eslint-disable */
} else if (command[0] === '\s') {
return <>&nbsp;{formatCommand(command.slice(1))}</>;
}
return command;
};
const formatCommand = (command) => {
if (command[0] === '\t') {
return <>&nbsp;&nbsp;&nbsp;&nbsp;{formatCommand(command.slice(1))}</>;
}
return command;
};
const renderCommands = () => {
return (
props.commands.map((command, index) => {
return (
<Code key={`command-${props.codeBlockIndex}-${index}`} as='li'
before={!props.disablePrompt}>
{formatCommand(command)}
</Code>
);
})
);
};
const renderCommands = () => {
return props.commands.map((command, index) => {
return (
<Code
key={`command-${props.codeBlockIndex}-${index}`}
as="li"
before={!props.disablePrompt}
>
{formatCommand(command)}
</Code>
);
});
};
return (
<CodeShellStyle as='ul' maxWidth={props.maxWidth}>
<Svg position='absolute' top='12px' right='12px' cursor='pointer'
backgroundColor={theme.colors.white} src={ico} onClick={clickCopyButton}/>
{ico === checkIco ? <CopiedMessageStyle>copied!</CopiedMessageStyle> : ''}
{renderCommands()}
</CodeShellStyle>
);
return (
<CodeShellStyle as="ul" maxWidth={props.maxWidth}>
<Svg
position="absolute"
top="12px"
right="12px"
cursor="pointer"
backgroundColor={theme.colors.white}
src={ico}
onClick={clickCopyButton}
/>
{ico === checkIco ? <CopiedMessageStyle>copied!</CopiedMessageStyle> : ''}
{renderCommands()}
</CodeShellStyle>
);
};
export default CodeShell;
export default CodeShell;

View File

@ -1,7 +1,7 @@
import React from 'react';
import { Container, FlexColumn, FlexRow, Svg } from '../../utils/containers';
import { useParams } from 'react-router-dom';
import { H1, H2, Medium } from '../../utils/fonts';
import { H1, Medium } from '../../utils/fonts';
import theme from '../../utils/theme';
import MobileChallengeMenu from './MobileChallengeMenu';
import Leaderboard from './Leaderboard/Leaderboard';
@ -48,7 +48,13 @@ const Challenge = (props) => {
/>
);
case 2:
return <HowTo challengeName={challengeName} user={user} />;
return (
<HowTo
popUpMessageHandler={props.popUpMessageHandler}
challengeName={challengeName}
user={user}
/>
);
case 3:
return <MyEntries challengeName={challengeName} />;
case 4:
@ -64,29 +70,33 @@ const Challenge = (props) => {
};
const mobileRender = () => {
return (
<FlexColumn
minHeight="100vh"
gap="12px"
alignmentY="flex-start"
padding="66px 0 0 0"
>
<Loading visible={loading} />
<H1 as="h1" margin="0 0 8px 0" textAlign="center">
{challenge.title}
</H1>
<MobileChallengeMenu
challengeName={challengeName}
section={props.section}
/>
<Container
width="75%"
height="1px"
backgroundColor={theme.colors.dark}
/>
{sectionRender()}
</FlexColumn>
);
if (!loading) {
return (
<FlexColumn
minHeight="100vh"
gap="12px"
alignmentY="flex-start"
padding="66px 0 0 0"
>
<Loading visible={loading} />
<H1 as="h1" margin="0 0 8px 0" textAlign="center">
{challenge.title}
</H1>
<MobileChallengeMenu
challengeName={challengeName}
section={props.section}
/>
<Container
width="75%"
height="1px"
backgroundColor={theme.colors.dark}
/>
{sectionRender()}
</FlexColumn>
);
} else {
return <Loading />;
}
};
const desktopRender = () => {
@ -125,19 +135,7 @@ const Challenge = (props) => {
</>
);
} else {
return (
<FlexColumn
position="fixed"
top="0"
left="0"
width="100%"
height="100vh"
zIndex="10"
>
<H2 as="h1">Submission processing...</H2>
<Loading />
</FlexColumn>
);
return <Loading />;
}
};

View File

@ -48,7 +48,7 @@ const DesktopChallengeMenu = (props) => {
<Option
key={`challenge_menu_option-${index}`}
as={Link}
active={index === props.section}
active={index === props.section ? 1 : 0}
to={`/challenge/${props.challengeName}/${options[index]
.toLowerCase()
.replace(' ', '')}`}

View File

@ -1,9 +1,25 @@
import React from 'react';
import getFullUser from '../../../api/getFullUserInfo';
import KeyCloakService from '../../../services/KeyCloakService';
import { FlexColumn } from '../../../utils/containers';
import { IS_MOBILE } from '../../../utils/globals';
import HowToContent from './sections/HowToContent';
const HowTo = (props) => {
const [userFullInfo, setUserFullInfo] = React.useState(null);
React.useEffect(() => {
getFullUser(setUserFullInfo);
if (!KeyCloakService.isLoggedIn()) {
props.popUpMessageHandler(
'Please log in',
'To see everything you must log in',
() => KeyCloakService.doLogin
);
}
}, [props]);
return (
<FlexColumn
margin={IS_MOBILE() ? null : '64px 0 0 0'}
@ -14,6 +30,7 @@ const HowTo = (props) => {
>
<FlexColumn maxWidth="680px" alignmentX="flex-start" gap="48px">
<HowToContent
userFullInfo={userFullInfo}
user={props.user ? props.user : 'yourID'}
challengeName={props.challengeName}
/>

View File

@ -17,6 +17,17 @@ const HowToContent = (props) => {
}
};
const repoKeyRender = () => {
if (props.userFullInfo) {
return (
<CodeShell
codeBlockIndex={0}
commands={[props.userFullInfo.individualKey]}
/>
);
}
};
return (
<FlexColumn
as="article"
@ -36,7 +47,7 @@ const HowToContent = (props) => {
<Body as="p" margin="auto 0">
Create a private git repository with the name
<Medium as="span">&nbsp;{props.challengeName}</Medium>
.&nbsp;The name of the repository must match!
&nbsp;The name of the repository must match!
</Body>
</Grid>
<Grid
@ -46,10 +57,12 @@ const HowToContent = (props) => {
>
<CircleNumber number="2" />
<Body as="p" margin="auto 0">
Add the following ssh key <Medium as="span">REPO_KEY_HERE</Medium> to
your deploy keys in your git repository settings.
Add the following ssh key{' '}
<Medium as="span">{props.userFullInfo ? '' : 'REPO_KEY_HERE'}</Medium>{' '}
to your deploy keys in your git repository settings.
</Body>
</Grid>
{repoKeyRender()}
<Grid
width="100%"
gridTemplateColumns="auto 1fr"

View File

@ -1,50 +1,89 @@
import React from 'react';
import {FlexColumn} from '../../utils/containers';
import {H2, Menu} from '../../utils/fonts';
import { createPortal } from 'react-dom';
import { FlexColumn } from '../../utils/containers';
import { H2, Menu } from '../../utils/fonts';
import SubmitInput from '../generic/SubmitInput';
import Button from '../generic/Button';
import theme from '../../utils/theme';
import challengeSubmission from '../../api/challengeSubmissionPost';
import Loading from '../generic/Loading';
const Submit = (props) => {
const [description, setDescription] = React.useState('');
const [repoUrl, setRepoUrl] = React.useState('');
const [repoBranch, setRepoBranch] = React.useState('');
const [description, setDescription] = React.useState('');
const [repoUrl, setRepoUrl] = React.useState('');
const [repoBranch, setRepoBranch] = React.useState('');
const [loading, setLoading] = React.useState(false);
const descriptionHandler = (e) => {
setDescription(e.target.value);
};
const descriptionHandler = (e) => {
setDescription(e.target.value);
};
const repoUrlHandler = (e) => {
setRepoUrl(e.target.value);
};
const repoUrlHandler = (e) => {
setRepoUrl(e.target.value);
};
const repoBranchHandler = (e) => {
setRepoBranch(e.target.value);
};
const repoBranchHandler = (e) => {
setRepoBranch(e.target.value);
};
const challengeSubmissionSubmit = () => {
challengeSubmission(props.challengeName, repoUrl, repoBranch, description, props.setLoading);
};
return (
<FlexColumn margin='40px 0 0 0' padding='24px' as='section' gap='64px' maxWidth='624px' width='100%'
alignmentX='flex-start'>
<H2 as='h2' width='100%' textAlign='center'>
Submit a solution to the challenge
</H2>
<FlexColumn width='100%' gap='32px'>
<SubmitInput label='Submission description' handler={descriptionHandler}/>
<SubmitInput label='Submission repo URL' handler={repoUrlHandler}/>
<SubmitInput label='Submission repo branch' handler={repoBranchHandler}/>
</FlexColumn>
<Button width='122px' height='44px' handler={challengeSubmissionSubmit}>
<Menu color={theme.colors.white}>
Submit
</Menu>
</Button>
</FlexColumn>
const challengeSubmissionSubmit = () => {
setLoading(true);
challengeSubmission(
props.challengeName,
repoUrl,
repoBranch,
description,
setLoading
);
};
if (!loading) {
return (
<FlexColumn
margin="40px 0 0 0"
padding="24px"
as="section"
gap="64px"
maxWidth="624px"
width="100%"
alignmentX="flex-start"
>
<H2 as="h2" width="100%" textAlign="center">
Submit a solution to the challenge
</H2>
<FlexColumn width="100%" gap="32px">
<SubmitInput
label="Submission description"
handler={descriptionHandler}
/>
<SubmitInput label="Submission repo URL" handler={repoUrlHandler} />
<SubmitInput
label="Submission repo branch"
handler={repoBranchHandler}
/>
</FlexColumn>
<Button width="122px" height="44px" handler={challengeSubmissionSubmit}>
<Menu color={theme.colors.white}>Submit</Menu>
</Button>
</FlexColumn>
);
} else {
return createPortal(
<FlexColumn
position="fixed"
top="0"
left="0"
width="100%"
height="100vh"
zIndex="100"
backgroundColor={theme.colors.white}
>
<H2 as="h1">Submission processing...</H2>
<Loading />
</FlexColumn>,
document.body
);
}
};
export default Submit;
export default Submit;

View File

@ -76,6 +76,8 @@ const Code = styled(Container)`
line-height: 18px;
font-weight: 300;
color: ${({theme}) => theme.colors.white};
max-width: 600px;
overflow-wrap: break-word;
&:before {
display: ${({before}) => before ? 'inline-block' : 'none'};