MyEntries with new table and logic

This commit is contained in:
Mateusz Tylka 2023-06-09 15:50:45 +02:00
parent e5d0e50102
commit b8b4c31b45
8 changed files with 194 additions and 256 deletions

View File

@ -1,13 +1,14 @@
import { API } from '../utils/globals'; import { API } from '../utils/globals';
import KeyCloakService from '../services/KeyCloakService'; import KeyCloakService from '../services/KeyCloakService';
const getAllEntries = ( const getEntries = (
endpoint,
challengeName, challengeName,
setDataStates, setDataStates,
setLoadingState, setLoadingState,
setScoreSorted setScoreSorted
) => { ) => {
fetch(`${API}/challenge-all-submissions/${challengeName}`, { fetch(`${API}/${endpoint}/${challengeName}`, {
headers: { Authorization: `Bearer ${KeyCloakService.getToken()}` }, headers: { Authorization: `Bearer ${KeyCloakService.getToken()}` },
}) })
.then((response) => response.json()) .then((response) => response.json())
@ -61,4 +62,4 @@ const getAllEntries = (
}); });
}; };
export default getAllEntries; export default getEntries;

View File

@ -3,9 +3,7 @@ import KeyCloakService from '../services/KeyCloakService';
const getMyEntries = ( const getMyEntries = (
challengeName, challengeName,
setDataOriginalState, setDataStates,
setDataStateForSearch,
setDataState,
setLoadingState, setLoadingState,
setScoreSorted setScoreSorted
) => { ) => {
@ -14,7 +12,6 @@ const getMyEntries = (
}) })
.then((response) => response.json()) .then((response) => response.json())
.then((data) => { .then((data) => {
setDataOriginalState(data);
let item = {}; let item = {};
let result = []; let result = [];
let initSetScoreSorted = []; let initSetScoreSorted = [];
@ -31,18 +28,17 @@ const getMyEntries = (
}; };
} }
for (let test of tests) { for (let test of tests) {
if (item.evaluations) { if (!item.evaluations) {
if ( item.evaluations = {};
!Object.hasOwn(item.evaluations, `${test.metric}.${test.name}`) }
) { if (!Object.hasOwn(item.evaluations, `${test.metric}.${test.name}`)) {
item = { item = {
...item, ...item,
evaluations: { evaluations: {
...item.evaluations, ...item.evaluations,
[`${test.metric}.${test.name}`]: '_', [`${test.metric}.${test.name}`]: -999999999,
}, },
}; };
}
} }
} }
item = { item = {
@ -50,6 +46,7 @@ const getMyEntries = (
id: submission.id, id: submission.id,
submitter: submission.submitter, submitter: submission.submitter,
when: submission.when, when: submission.when,
tags: submission.tags,
}; };
result.push(item); result.push(item);
item = {}; item = {};
@ -58,10 +55,9 @@ const getMyEntries = (
for (let _ of tests) { for (let _ of tests) {
initSetScoreSorted.push(false); initSetScoreSorted.push(false);
} }
setScoreSorted(initSetScoreSorted); for (let setDataState of setDataStates) setDataState(result);
setDataStateForSearch(result); if (setScoreSorted) setScoreSorted(initSetScoreSorted);
setDataState(result); if (setLoadingState) setLoadingState(false);
setLoadingState(false);
}); });
}; };

View File

@ -3,7 +3,7 @@ import { FlexColumn } from '../../utils/containers';
import { H2 } from '../../utils/fonts'; import { H2 } from '../../utils/fonts';
import Pager from '../../components/generic/Pager'; import Pager from '../../components/generic/Pager';
import Search from '../../components/generic/Search'; import Search from '../../components/generic/Search';
import getAllEntries from '../../api/getAllEntries'; import getEntries from '../../api/getEntries';
import Table from '../../components/generic/Table'; import Table from '../../components/generic/Table';
import Loading from '../../components/generic/Loading'; import Loading from '../../components/generic/Loading';
import { CALC_PAGES, ELEMENTS_PER_PAGE } from '../../utils/globals'; import { CALC_PAGES, ELEMENTS_PER_PAGE } from '../../utils/globals';
@ -22,7 +22,8 @@ const NewTablePageTest = (props) => {
React.useMemo(() => { React.useMemo(() => {
if (props.challengeName) { if (props.challengeName) {
getAllEntries( getEntries(
'challenge-all-submissions',
props.challengeName, props.challengeName,
[setEntries, setEntriesAll], [setEntries, setEntriesAll],
setLoading, setLoading,

View File

@ -5,9 +5,19 @@ const searchQueryHandler = (event, entriesAll, setPageNr, setEntries) => {
if (searchQuery === '') setEntries(entriesAll); if (searchQuery === '') setEntries(entriesAll);
else { else {
for (let entry of entriesAll) { for (let entry of entriesAll) {
const { when } = entry; let { when, tags } = entry;
const otherKeys = Object.values(entry).join(' '); tags = Object.values(tags)
const str = `${when.slice(11, 16)} ${when.slice(0, 10)} ${otherKeys}`; .map((tag) => tag.name)
.join(' ');
const otherKeys = Object.values(entry)
.join(' ')
.replaceAll(-999999999, 'N/A')
.replaceAll('[object Object]', '')
.replaceAll(',', '');
const str = `${when.slice(11, 16)} ${when.slice(
0,
10
)} ${otherKeys} ${tags}`;
if (str.toLowerCase().includes(searchQuery.toLowerCase())) if (str.toLowerCase().includes(searchQuery.toLowerCase()))
submissionsToRender.push(entry); submissionsToRender.push(entry);
} }

View File

@ -1,220 +1,132 @@
import React from 'react'; import React from 'react';
import { FlexColumn } from '../../utils/containers'; import { FlexColumn } from '../../utils/containers';
import { H2 } from '../../utils/fonts'; import { H2 } from '../../utils/fonts';
import getMyEntries from '../../api/getMyEntries';
import Pager from '../../components/generic/Pager'; import Pager from '../../components/generic/Pager';
import { import { CALC_PAGES } from '../../utils/globals';
CALC_PAGES,
EVALUATIONS_FORMAT,
IS_MOBILE,
RENDER_WHEN,
} from '../../utils/globals';
import Media from 'react-media';
import theme from '../../utils/theme';
import Loading from '../../components/generic/Loading'; import Loading from '../../components/generic/Loading';
import Table from '../../components/generic/Table/Table'; import Table from '../../components/generic/Table/Table';
import myEntriesSearchQueryHandler from './myEntriesSearchQueryHandler';
import Search from '../../components/generic/Search'; import Search from '../../components/generic/Search';
import orderKeys from './orderKeys';
import { ELEMENTS_PER_PAGE } from '../../utils/globals';
import getEntries from '../../api/getEntries';
import searchHandler from './searchHandler';
const MyEntries = (props) => { const MyEntries = (props) => {
const [myEntriesFromAPI, setMyEntriesFromAPI] = React.useState({}); // const [myEntriesFromAPI, setMyEntriesFromAPI] = React.useState({});
const [myEntriesAll, setMyEntriesAll] = React.useState({}); const [myEntriesAll, setMyEntriesAll] = React.useState([]);
const [myEntries, setMyEntries] = React.useState({}); const [myEntries, setMyEntries] = React.useState([]);
const [loading, setLoading] = React.useState(true); const [loading, setLoading] = React.useState(true);
const [pageNr, setPageNr] = React.useState(1); const [pageNr, setPageNr] = React.useState(1);
const [idSorted, setIdSorted] = React.useState([]);
const [whenSorted, setWhenSorted] = React.useState(false); const [whenSorted, setWhenSorted] = React.useState(false);
const [scoresSorted, setScoresSorted] = React.useState([]); const [scoresSorted, setScoresSorted] = React.useState([]);
React.useEffect(() => { React.useMemo(() => {
challengesRequest(); getEntries(
// eslint-disable-next-line 'challenge-my-submissions',
}, []);
const searchQueryHandler = (event) => {
myEntriesSearchQueryHandler(event, myEntriesAll, setPageNr, setMyEntries);
};
const getPossibleMetrics = () => {
let metrics = [];
for (let test of myEntriesFromAPI.tests) {
let myEval = `${test.metric}.${test.name}`;
if (myEval && !metrics.includes(myEval)) {
metrics.push(myEval);
}
}
return metrics;
};
const getMyEntriesHeader = () => {
let header = ['#'];
if (IS_MOBILE()) header.push('when');
for (let myEval of getPossibleMetrics()) {
header.push(myEval);
}
if (!IS_MOBILE()) header.push('when');
return header;
};
const challengesRequest = () => {
getMyEntries(
props.challengeName, props.challengeName,
setMyEntriesFromAPI, [setMyEntries, setMyEntriesAll],
setMyEntriesAll,
setMyEntries,
setLoading, setLoading,
setScoresSorted setScoresSorted
); );
}; }, [props.challengeName]);
const sortByUpdate = (elem, i) => { const sortByUpdate = React.useCallback(
let newEntries = myEntries; (elem) => {
switch (elem) { let newEntries = myEntries.slice();
case '#': const possibleMetrics = orderKeys(myEntries[0]).filter(
break; (key) => !['id', 'submitter', 'when'].includes(key)
case 'when': );
if (whenSorted) { let metricIndex = possibleMetrics.indexOf(elem);
newEntries = newEntries.sort((a, b) => let newScoresSorted = scoresSorted.slice();
a.when < b.when ? 1 : b.when < a.when ? -1 : 0 switch (elem) {
); case 'id':
setWhenSorted(false); if (idSorted) {
} else { setIdSorted(false);
newEntries = newEntries.sort((a, b) => newEntries = newEntries.sort((a, b) =>
a.when > b.when ? 1 : b.when > a.when ? -1 : 0 a.id > b.id ? 1 : b.id > a.id ? -1 : 0
); );
setWhenSorted(true); } else {
} setIdSorted(true);
break; newEntries = newEntries.sort((a, b) =>
default: a.id < b.id ? 1 : b.id < a.id ? -1 : 0
// eslint-disable-next-line no-case-declarations );
let metricIndex = getPossibleMetrics().indexOf(elem); }
// eslint-disable-next-line no-case-declarations break;
let newScoresSorted = scoresSorted; case 'when':
if (scoresSorted[metricIndex]) { if (whenSorted) {
newEntries = newEntries.sort( setWhenSorted(false);
(a, b) => newEntries = newEntries.sort((a, b) =>
(b.evaluations ? b.evaluations[elem] : -1) - a.when < b.when ? 1 : b.when < a.when ? -1 : 0
(a.evaluations ? a.evaluations[elem] : -1) );
); } else {
newScoresSorted[metricIndex] = false; setWhenSorted(true);
setScoresSorted(newScoresSorted); newEntries = newEntries.sort((a, b) =>
} else { a.when > b.when ? 1 : b.when > a.when ? -1 : 0
newEntries = newEntries.sort( );
(a, b) => }
(a.evaluations ? a.evaluations[elem] : -1) - break;
(b.evaluations ? b.evaluations[elem] : -1) default:
); if (scoresSorted[metricIndex]) {
newScoresSorted[metricIndex] = true; newEntries = newEntries.sort(
setScoresSorted(newScoresSorted); (a, b) => (b ? b[elem] : -1) - (a ? a[elem] : -1)
} );
break; newScoresSorted[metricIndex] = false;
} setScoresSorted(newScoresSorted);
setMyEntries(newEntries); } else {
}; newEntries = newEntries.sort(
(a, b) => (a ? a[elem] : -1) - (b ? b[elem] : -1)
);
newScoresSorted[metricIndex] = true;
setScoresSorted(newScoresSorted);
}
break;
}
setMyEntries(newEntries);
},
[idSorted, myEntries, scoresSorted, whenSorted]
);
const mobileRender = () => { const n = (pageNr - 1) * (ELEMENTS_PER_PAGE * 2);
return ( let elements = myEntries.slice(n, n + ELEMENTS_PER_PAGE * 2);
<FlexColumn padding="24px 12px" width="70%" as="section" id="start">
<H2 as="h2" margin="0 0 12px 0">
My Entries
</H2>
{!loading ? (
<>
<Search searchQueryHandler={searchQueryHandler} />
<Table
challengeName={props.challengeName}
headerElements={getMyEntriesHeader()}
possibleMetrics={getPossibleMetrics()}
tableType="myEntries"
gridTemplateColumns={
'1fr ' + '4fr '.repeat(getMyEntriesHeader().length - 1)
}
staticColumnElements={[
{ name: 'id', format: null, order: 1, align: 'left' },
{ name: 'when', format: RENDER_WHEN, order: 3, align: 'right' },
]}
iterableColumnElement={{
name: 'evaluations',
format: EVALUATIONS_FORMAT,
order: 2,
align: 'left',
}}
pageNr={pageNr}
elements={myEntries}
sortByUpdate={sortByUpdate}
/>
<Pager
pageNr={pageNr}
elements={myEntries}
setPageNr={setPageNr}
width="48px"
borderRadius="64px"
pages={CALC_PAGES(myEntries)}
number={`${pageNr} / ${CALC_PAGES(myEntries)}`}
/>
</>
) : (
<Loading />
)}
</FlexColumn>
);
};
const desktopRender = () => {
return (
<FlexColumn padding="24px" as="section" width="100%" maxWidth="1600px">
<FlexColumn padding="24px 12px" width="70%" as="section" id="start">
<H2 as="h2" margin="0 0 32px 0">
My Entries
</H2>
</FlexColumn>
{myEntries && !loading ? (
<>
<Search searchQueryHandler={searchQueryHandler} />
<Table
challengeName={props.challengeName}
headerElements={getMyEntriesHeader()}
possibleMetrics={getPossibleMetrics()}
gridTemplateColumns={
'1fr ' + '3fr '.repeat(getMyEntriesHeader().length - 2) + ' 4fr'
}
staticColumnElements={[
{ name: 'id', format: null, order: 1, align: 'left' },
{ name: 'when', format: RENDER_WHEN, order: 3, align: 'right' },
]}
iterableColumnElement={{
name: 'evaluations',
format: EVALUATIONS_FORMAT,
order: 2,
align: 'left',
}}
pageNr={pageNr}
elements={myEntries}
sortByUpdate={sortByUpdate}
myEntries
/>
<Pager
pageNr={pageNr}
elements={myEntries}
setPageNr={setPageNr}
width="72px"
mobileRender
borderRadius="64px"
pages={CALC_PAGES(myEntries, 2)}
number={`${pageNr} / ${CALC_PAGES(myEntries, 2)}`}
/>
</>
) : (
<Loading />
)}
</FlexColumn>
);
};
return ( return (
<> <FlexColumn
<Media query={theme.mobile}>{mobileRender()}</Media> padding="24px"
<Media query={theme.desktop}>{desktopRender()}</Media> gap="32px"
</> as="section"
width="100%"
maxWidth="1600px"
>
<H2 as="h2">My Entries</H2>
{!loading ? (
<>
<Search
searchQueryHandler={(event) =>
searchHandler(event, myEntriesAll, setPageNr, setMyEntries)
}
/>
{elements.length > 0 && myEntries[0] && (
<Table
items={elements}
orderedKeys={orderKeys(myEntries[0])}
sortByUpdate={sortByUpdate}
/>
)}
<Pager
pageNr={pageNr}
elements={myEntries}
setPageNr={setPageNr}
width="72px"
borderRadius="64px"
pages={CALC_PAGES(myEntries, 2)}
number={`${pageNr} / ${CALC_PAGES(myEntries, 2)}`}
/>
</>
) : (
<Loading />
)}
</FlexColumn>
); );
}; };

View File

@ -1,33 +0,0 @@
const myEntriesSearchQueryHandler = (
event,
entriesFromApi,
setPageNr,
setEntries
) => {
let searchQuery = event.target.value;
let submissionsToRender = [];
setPageNr(1);
if (searchQuery === '') setEntries(entriesFromApi);
else {
for (let entry of entriesFromApi) {
const { id, when } = entry;
let evaluations = '';
if (entry.evaluations) {
for (let evaluation of Object.values(entry.evaluations)) {
evaluations += ` ${evaluation}`;
}
}
const str = `${id} ${when.slice(11, 16)} ${when.slice(
0,
10
)} ${evaluations}`;
console.log(entry);
console.log(str);
if (str.toLowerCase().includes(searchQuery.toLowerCase()))
submissionsToRender.push(entry);
}
setEntries(submissionsToRender);
}
};
export default myEntriesSearchQueryHandler;

View File

@ -0,0 +1,23 @@
const orderKeys = (elem) => {
if (elem) {
let result = ['id'];
const elemKeys = Object.keys(elem);
const dev0keys = elemKeys
.filter((key) => key.split('.')[1] === 'dev-0')
.sort();
const dev1keys = elemKeys
.filter((key) => key.split('.')[1] === 'dev-1')
.sort();
const testAkeys = elemKeys
.filter((key) => key.split('.')[1] === 'test-A')
.sort();
result = result.concat(dev0keys);
result = result.concat(dev1keys);
result = result.concat(testAkeys);
result.push('when');
return result;
}
return null;
};
export default orderKeys;

View File

@ -0,0 +1,28 @@
const searchQueryHandler = (event, entriesAll, setPageNr, setEntries) => {
let searchQuery = event.target.value;
let submissionsToRender = [];
setPageNr(1);
if (searchQuery === '') setEntries(entriesAll);
else {
for (let entry of entriesAll) {
let { when, tags } = entry;
tags = Object.values(tags)
.map((tag) => tag.name)
.join(' ');
const otherKeys = Object.values(entry)
.join(' ')
.replaceAll(-999999999, 'N/A')
.replaceAll('[object Object]', '')
.replaceAll(',', '');
const str = `${when.slice(11, 16)} ${when.slice(
0,
10
)} ${otherKeys} ${tags}`;
if (str.toLowerCase().includes(searchQuery.toLowerCase()))
submissionsToRender.push(entry);
}
setEntries(submissionsToRender);
}
};
export default searchQueryHandler;