Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migate Run Validators page to react #10652

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

danieljames-dj
Copy link
Member

This is part of migrating all panel pages to react

Comment on lines +54 to +62
validators = params.require(:selectedValidators).split(',').map(&:constantize)
apply_fix_when_possible = params.require(:applyFixWhenPossible)

results_validator = ResultsValidators::CompetitionsResultsValidator.new(
validators,
check_real_results: true,
apply_fixes: apply_fix_when_possible,
)
results_validator.validate(competition_ids)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As useful as constantize is, you gotta be careful with when and how you use it because it can potentially lead to vulnerabilities. In this context, I'm wondering: Why didn't you use the existing result_validation_form.rb that is also used in the previous running_validators hook?

const {
data: competitionList, isLoading, isError, refetch,
} = useQuery({
queryKey: ['competitionCountInRange'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The startDate and endDate need to be included in the queryKey. Otherwise, the query will never be refetched when the dates change, and the old number will persist.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For your basic understanding, you can think of queryKey as a cache key that controls the "cache" of the network traffic, to make sure that the data is only refetched when needed. (The real implementation is a bit more complex than that, but as a rule of thumb the cache comparison works.)


export default async function getCompetitionList(startDate, endDate, maxLimit) {
const { data } = await fetchJsonOrError(
`${apiV0Urls.competitions.listIndex}?start=${startDate}&end=${endDate}&per_page=${maxLimit}`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are you not using the admin_validation_competitions_path URL from the old jQuery form?
Don't get me wrong, I would love it if we can switch to (semi-)public APIs, but I just really want to make sure they return the same results.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One advantage of a custom path would be that you can serialize only the names, and avoid sending (or even loading from the DB) any unnecessary extra data.

Comment on lines +26 to +31
useEffect(() => {
setRange({ startDate, endDate });
if (enableCompetitionListFetch) {
refetch();
}
}, [startDate, endDate, setRange, enableCompetitionListFetch, refetch]);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook definitely needs to go. react-query should only be refetched in rare circumstances, but right here is a basic use-case which should be fixed by adjusting the query key as noted in my comment above.

Comment on lines +58 to +62
<div>
{`The checks will run for ${competitionList.length}${
competitionList.length >= MAX_COMPETITIONS_PER_QUERY ? '+' : ''
} competitions`}
</div>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need this wrapping div? In case of doubt, a <> fragment should do


return (
<>
<Form onSubmit={runValidators}>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! I think what you want are React-Query Mutations: https://tanstack.com/query/latest/docs/framework/react/guides/mutations

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(This also explains why you hard-coded enabled: false above, which definitely still is an anti-pattern.)

Comment on lines +110 to +119
<Form.Field
label="Competition ID(s)"
control={IdWcaSearch}
name="competitionIds"
value={selectedCompetitionIds}
onChange={setSelectedCompetitionIds}
model={SEARCH_MODELS.competition}
multiple
required
/>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation looks a little bit off here? Might just be the GitHub diff though.

Comment on lines +142 to +144
label={`Apply fix when possible (List of validators with automated fix: ${
VALIDATORS_WITH_FIX.map(validatorNameReadable).join(', ')
})`}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit awkward to have such a (potentially) long list as part of the checkbox label. Can you add them as an extra text paragraph below?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SemUI Header as h4 or h5 with only the subheader and no "real" header should do: https://react.semantic-ui.com/elements/header/#content-subheader

Comment on lines +46 to +50
[
<a href={competitionUrl(validationData.competition_id)}>
{validationData.competition_id}
</a>
{'] '}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need the []? Are they absolutely essential for user communication?

if (isFetching) return <Loading />;
if (isError) return <Errored />;

if (!isFetching && !isError && !validationOutput) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this point, you already know that !isFetching && !isError will always be true. Otherwise, the code would have returned already. So just checking !validationOutput should be enough.

const [startDate, setStartDate] = useState(range?.startDate);
const [endDate, setEndDate] = useState(range?.endDate);

const enableCompetitionListFetch = Boolean(startDate && endDate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm strongly in favour of naming things based on what they are, not how they are used.

Suggested change
const enableCompetitionListFetch = Boolean(startDate && endDate);
const bothDatesAreSelected = Boolean(startDate && endDate);

Comment on lines +13 to +14
const [startDate, setStartDate] = useState(range?.startDate);
const [endDate, setEndDate] = useState(range?.endDate);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we have these states here in the component? If we're receiving range and setRange then the parent should be updating range when setRange is called, and const startDate = range?.startDate will work.

isoDate={endDate}
onChange={setEndDate}
/>
{enableCompetitionListFetch && (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this required? I think removing it and have competitionList && ... for the third case would be better, assuming it works.

return (
<>
{Object.entries(listByGroup).map(([group, list]) => (
<>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure the console will be warning you that you need a key here.

<Header as="h5">{`${headingPrefixForType(type)} ${group}`}</Header>
<List bulleted>
{list.map((validationData) => (
<ListItem>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants