-
Notifications
You must be signed in to change notification settings - Fork 186
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
base: main
Are you sure you want to change the base?
Conversation
900e926
to
f0412cb
Compare
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't use the result_validation_form.rb
because it was having too many things. I agree those were good, but I feel that if I forcefully use that model, it may not be so clean. So just took the above two lines from that.
I just now saw couple of validations from the model which are also relevant, I've now implemented those validations in the client side.
I understand the risk of constantize
, I now see how the result_validation_form
is doing it - I have now changed to a similar logic, so no more use of constantize
.
Also, now I think technically result_validation_form.rb
is not needed anymore as it was used to support the rails ERB code, and that code is no longer there. So I've removed result_validation_form.rb
after making necessary changes.
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
|
||
export default async function getCompetitionList(startDate, endDate, maxLimit) { | ||
const { data } = await fetchJsonOrError( | ||
`${apiV0Urls.competitions.listIndex}?start=${startDate}&end=${endDate}&per_page=${maxLimit}`, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't think of the admin_validation_competitions_path
actually. But as part of one more cleanup, I actually removed ResultValidationForm
, and hence all it's usages which includes admin_validation_competitions_path
as well. But I've now created a new API to fetch the count of competitions. Hope that is fine.
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
Outdated
Show resolved
Hide resolved
[ | ||
<a href={competitionUrl(validationData.competition_id)}> | ||
{validationData.competition_id} | ||
</a> | ||
{'] '} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The users are WRT, it will look clean if the competition is added at the beginning of the validation info.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, interesting that the [
above is acceptable but ]
is not. Are there HTML codes (similar to &apost;
) that you could use?
app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationOutput.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationListView.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationListView.jsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the detailed review, @gregorbg. One of the main change that I did post last commit is that I removed result_validation_form
. I'm not sure if you are against it, but just to strengthen my argument, I like to highlight that the reason I felt to remove result_validation_form
is because this was a helper model for the rails UI, and the rails UI no longer exists, and everything done inside result_validation_form
can now be done in 2-3 lines.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't use the result_validation_form.rb
because it was having too many things. I agree those were good, but I feel that if I forcefully use that model, it may not be so clean. So just took the above two lines from that.
I just now saw couple of validations from the model which are also relevant, I've now implemented those validations in the client side.
I understand the risk of constantize
, I now see how the result_validation_form
is doing it - I have now changed to a similar logic, so no more use of constantize
.
Also, now I think technically result_validation_form.rb
is not needed anymore as it was used to support the rails ERB code, and that code is no longer there. So I've removed result_validation_form.rb
after making necessary changes.
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
Outdated
Show resolved
Hide resolved
import runValidatorsForCompetitionsInRange from './api/runValidatorsForCompetitionsInRange'; | ||
import ValidationOutput from './ValidationOutput'; | ||
|
||
const validatorNameReadable = (validatorName) => validatorName.split('::')[1]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have changed the logic for the validator name, so this is no longer there.
[ | ||
<a href={competitionUrl(validationData.competition_id)}> | ||
{validationData.competition_id} | ||
</a> | ||
{'] '} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The users are WRT, it will look clean if the competition is added at the beginning of the validation info.
queryKey: ['competitionCountInRange'], | ||
queryFn: runValidatorsForCompetitions, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ya it was a copy-paste, I forgot to change the key. I've anyway changed to useMutation
as you suggested, so no longer relevant.
} = useQuery({ | ||
queryKey: ['competitionCountInRange'], | ||
queryFn: runValidatorsForCompetitions, | ||
enabled: false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed.
app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
Outdated
Show resolved
Hide resolved
app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationOutput.jsx
Outdated
Show resolved
Hide resolved
6553fc2
to
0468c2f
Compare
84f85c7
to
5f50197
Compare
def competition_count | ||
start_date = params.require(:startDate) | ||
end_date = params.require(:endDate) | ||
|
||
count = Competition.where("start_date >= ? AND end_date <= ?", start_date, end_date).count | ||
render json: { count: count } | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a highly specific endpoint for internal uses, I'd rather not have that as part of the public API.
Competition.over | ||
.not_cancelled | ||
.where(start_date: start_date..) | ||
.where(start_date: ..end_date) | ||
.order(:start_date) | ||
.ids |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you combine this with the logic for competition_count
above?
Like, have some competitions_between(start, end)
method which returns Competition.over.not_cancelled.where(...).order(...)
and then one endpoint returns competitions_between(foo, bar).count
and the other one returns competitions_between(foo, bar).ids
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like the perfect use case for an AR scope
by the way :)
end | ||
|
||
def validators_for_competitions_in_range | ||
range = JSON.parse(params.require(:competitionRange)).transform_keys(&:to_sym) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...Why are you not simply passing in startDate
and endDate
as params directly?
queryKey: ['competitionCountInRange', range?.startDate, range?.endDate], | ||
queryFn: () => getCompetitionCount(range?.startDate, range?.endDate), | ||
enabled: bothDatesAreSelected, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the query is only enabled when both dates are selected, then you should be able to drop the ?
at least from the queryFn
|
||
const RUN_VALIDATORS_QUERY_CLIENT = new QueryClient(); | ||
|
||
export default function CompetitionRangeSelector({ range, setRange }) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you passing in range
instead of just passing the dates separately?
[ | ||
<a href={competitionUrl(validationData.competition_id)}> | ||
{validationData.competition_id} | ||
</a> | ||
{'] '} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Huh, interesting that the [
above is acceptable but ]
is not. Are there HTML codes (similar to &apost;
) that you could use?
if (!validationOutput) { | ||
return ( | ||
<Message>Please run the validators to see the output.</Message> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the validators have been run but still didn't give any output?
return ( | ||
<> | ||
{Object.entries(listByGroup).map(([group, list]) => ( | ||
<Fragment key={group}> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of Fragment
, you could consider wrapping this in a Message
. SemUI Messages have info
, warning
and error
states with nice color codings :)
function ValidationErrorOutput({ validationOutput, showCompetitionNameOnOutput }) { | ||
const hasResults = validationOutput.has_results; | ||
const hasErrors = validationOutput.errors.length > 0; | ||
|
||
if (!hasErrors) { | ||
if (hasResults) { | ||
return <p>No error detected in the results.</p>; | ||
} | ||
return <p>No results for the competition yet.</p>; | ||
} | ||
|
||
return ( | ||
<> | ||
<p>Please fix the errors below:</p> | ||
<ValidationListView | ||
validations={validationOutput.errors} | ||
showCompetitionNameOnOutput={showCompetitionNameOnOutput} | ||
type="error" | ||
/> | ||
</> | ||
); | ||
} | ||
|
||
function ValidationWarningOutput({ validationOutput, showCompetitionNameOnOutput }) { | ||
const hasResults = validationOutput.has_results; | ||
const hasWarning = validationOutput.warnings.length > 0; | ||
|
||
if (!hasWarning) { | ||
if (hasResults) { | ||
return <p>No warning detected in the results.</p>; | ||
} | ||
return <p>No results for the competition yet.</p>; | ||
} | ||
|
||
return ( | ||
<> | ||
<p>Please pay attention to the warnings below:</p> | ||
<ValidationListView | ||
validations={validationOutput.warnings} | ||
showCompetitionNameOnOutput={showCompetitionNameOnOutput} | ||
type="warning" | ||
/> | ||
</> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quite a lot of repetition, any chance to unify this?
You could consider changing the English texts a little, like No messages of type ${type} detected in the results
, to make reusing the components a bit easier
|
||
export default async function getCompetitionCount(startDate, endDate) { | ||
const { data } = await fetchJsonOrError(viewUrls.competitions.countInRange(startDate, endDate)); | ||
return data?.count; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, now you're accessing the data already again. If only the count is so important, then why not just return it directly from the backend?
(Yes, numbers by themselves are valid JSON. Not everything has to be {}
or []
on top level)
This is part of migrating all panel pages to react