From f0412cb3eb2b8b1e61e415e1cb05c2155b1882bd Mon Sep 17 00:00:00 2001
From: Daniel James
Date: Sun, 19 Jan 2025 09:10:18 +0530
Subject: [PATCH] Migate Run Validators page to react
---
app/controllers/admin_controller.rb | 10 --
app/controllers/panel_controller.rb | 39 +++++
app/views/admin/_validator_form.html.erb | 152 -----------------
.../admin/check_competition_results.html.erb | 5 +-
app/views/admin/check_results.html.erb | 10 --
app/webpacker/components/Panel/PanelPages.jsx | 4 +-
.../CompetitionRangeSelector.jsx | 68 ++++++++
.../RunValidatorsPage/RunValidatorsForm.jsx | 158 ++++++++++++++++++
.../RunValidatorsPage/ValidationListView.jsx | 56 +++++++
.../RunValidatorsPage/ValidationOutput.jsx | 90 ++++++++++
.../api/getCompetitionList.js | 9 +
.../api/runValidatorsForCompetitionList.js | 15 ++
.../runValidatorsForCompetitionsInRange.js | 15 ++
app/webpacker/lib/requests/routes.js.erb | 6 +-
app/webpacker/lib/wca-data.js.erb | 4 +
config/routes.rb | 5 +-
16 files changed, 465 insertions(+), 181 deletions(-)
delete mode 100644 app/views/admin/_validator_form.html.erb
delete mode 100644 app/views/admin/check_results.html.erb
create mode 100644 app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
create mode 100644 app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
create mode 100644 app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationListView.jsx
create mode 100644 app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationOutput.jsx
create mode 100644 app/webpacker/components/Panel/pages/RunValidatorsPage/api/getCompetitionList.js
create mode 100644 app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionList.js
create mode 100644 app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionsInRange.js
diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb
index db8b9855e5c..010f91ad671 100644
--- a/app/controllers/admin_controller.rb
+++ b/app/controllers/admin_controller.rb
@@ -33,10 +33,6 @@ def new_results
@results_validator.validate(@competition.id)
end
- def check_results
- with_results_validator
- end
-
def check_competition_results
with_results_validator do
@competition = competition_from_params
@@ -72,12 +68,6 @@ def with_results_validator
yield if block_given?
end
- def do_check_results
- running_validators do
- render :check_results
- end
- end
-
def do_check_competition_results
running_validators do
uniq_id = @result_validation.competitions.first
diff --git a/app/controllers/panel_controller.rb b/app/controllers/panel_controller.rb
index 92ed2271cbf..fcc69b95147 100644
--- a/app/controllers/panel_controller.rb
+++ b/app/controllers/panel_controller.rb
@@ -50,6 +50,45 @@ def generate_db_token
}
end
+ private def validators_for_competition_ids(competition_ids)
+ 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)
+ render json: {
+ has_results: results_validator.has_results?,
+ validators: results_validator.validators,
+ infos: results_validator.infos,
+ errors: results_validator.errors,
+ warnings: results_validator.warnings,
+ }
+ end
+
+ private def competition_ids_in_range(range)
+ start_date = range[:startDate]
+ end_date = range[:endDate]
+ ResultValidationForm.competitions_between(start_date, end_date)
+ .order(:start_date)
+ .ids
+ end
+
+ def validators_for_competition_list
+ competition_ids = params.require(:competitionIds).split(',')
+ validators_for_competition_ids(competition_ids)
+ end
+
+ def validators_for_competitions_in_range
+ range = JSON.parse(params.require(:competitionRange)).transform_keys(&:to_sym)
+ competition_ids = competition_ids_in_range(range)
+
+ validators_for_competition_ids(competition_ids)
+ end
+
def panel_page
panel_page_id = params.require(:id)
panel_with_panel_page = current_user.panels_with_access&.find { |panel| User.panel_list[panel][:pages].include?(panel_page_id) }
diff --git a/app/views/admin/_validator_form.html.erb b/app/views/admin/_validator_form.html.erb
deleted file mode 100644
index 97e247f925b..00000000000
--- a/app/views/admin/_validator_form.html.erb
+++ /dev/null
@@ -1,152 +0,0 @@
-<% backend_url ||= nil %>
-<% lock_selection = defined? @competition %>
-
-
Configure validations to run
-
- <%= simple_form_for @result_validation, url: backend_url do |f| %>
- <%= f.input :validator_classes, as: :string, label: false, hint: false, input_html: { id: "validators" } %>
- <%= f.input :apply_fixes, as: :boolean, label: "Apply fix when possible", hint: "List of validators with automated fix: #{ResultValidationForm::VALIDATOR_WITH_FIX_NAMES.join(",")}." %>
- <% unless lock_selection %>
- <%= f.input :competition_selection, collection: ResultValidationForm::COMP_VALIDATION_MODES, as: :radio_buttons, label: "Competition selection", hint: "WARNING: Running multiple validations on all competitions can take a long time." %>
- <% end %>
-
- <%= f.input :competition_ids, as: :competition_id, hint: false, label: "Competition ID(s)", input_html: { class: lock_selection ? "wca-autocomplete-input_lock" : "" } %>
-
- <% unless lock_selection %>
-
- <%= f.input :competition_start_date, as: :date_picker, hint: false, label: "Start date for checking" %>
- <%= f.input :competition_end_date, as: :date_picker, hint: "Please pick dates above to update this label with information on the selected competitions.", label: "End date for checking" %>
-
-
-
- <% end %>
-
- <%= f.button :submit, value: "Run validators", class: "btn-primary" %>
- <%= ui_icon('info circle', 'data-toggle': "collapse", 'data-target': "#collapse-validator-desc") %>
-
-
- <%= wca_table do %>
-
-
- Validator |
- Description |
- |
-
-
-
- <% ResultsValidators::Utils::ALL_VALIDATORS.each do |validator| %>
-
- <%= validator.class_name %> |
- <%= validator.description %> |
- |
-
- <% end %>
-
- <% end %>
-
- <% end %>
-
-
-
-
-
diff --git a/app/views/admin/check_competition_results.html.erb b/app/views/admin/check_competition_results.html.erb
index 3bfc67f2d06..0b0761d79f1 100644
--- a/app/views/admin/check_competition_results.html.erb
+++ b/app/views/admin/check_competition_results.html.erb
@@ -5,8 +5,9 @@
Check existing results for the competition.
- <%= render "validator_form", backend_url: competition_admin_run_validators_path %>
- <%= render "results_submission/check_results_panel", results_validator: @results_validator %>
+ <%= react_component("Panel/pages/RunValidatorsPage/RunValidatorsForm", {
+ competitionIds: [@competition.id],
+ }) %>
<%= render "results_submission/results_preview_panel", results_validator: @results_validator %>
<% end %>
diff --git a/app/views/admin/check_results.html.erb b/app/views/admin/check_results.html.erb
deleted file mode 100644
index 4a2b9ca2c6a..00000000000
--- a/app/views/admin/check_results.html.erb
+++ /dev/null
@@ -1,10 +0,0 @@
-<% provide(:title, "Check results") %>
-
-
Run validators
-
- Check existing results.
-
-
- <%= render "validator_form", backend_url: admin_check_results_path %>
- <%= render "results_submission/check_results_panel", results_validator: @results_validator, display_competition: @result_validation.competitions.length > 1 %>
-
diff --git a/app/webpacker/components/Panel/PanelPages.jsx b/app/webpacker/components/Panel/PanelPages.jsx
index 369264676ff..ee29d9992b8 100644
--- a/app/webpacker/components/Panel/PanelPages.jsx
+++ b/app/webpacker/components/Panel/PanelPages.jsx
@@ -5,7 +5,6 @@ import {
subordinateUpcomingCompetitionsUrl,
generateDbTokenUrl,
serverStatusPageUrl,
- runValidatorsUrl,
createNewComersUrl,
checkRecordsUrl,
computeAuxiliaryDataUrl,
@@ -39,6 +38,7 @@ import DownloadVoters from './pages/DownloadVoters';
import ApprovePictures from './pages/ApprovePictures';
import EditPersonRequestsPage from './pages/EditPersonRequestsPage';
import AnonymizationScriptPage from './pages/AnonymizationScriptPage';
+import RunValidatorsForm from './pages/RunValidatorsPage/RunValidatorsForm';
const DELEGATE_HANDBOOK_LINK = 'https://documents.worldcubeassociation.org/edudoc/delegate-handbook/delegate-handbook.pdf';
@@ -165,7 +165,7 @@ export default {
},
[PANEL_PAGES.runValidators]: {
name: 'Run Validators',
- link: runValidatorsUrl,
+ component: RunValidatorsForm,
},
[PANEL_PAGES.createNewComers]: {
name: 'Create New Comers',
diff --git a/app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx b/app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
new file mode 100644
index 00000000000..faaab9d477b
--- /dev/null
+++ b/app/webpacker/components/Panel/pages/RunValidatorsPage/CompetitionRangeSelector.jsx
@@ -0,0 +1,68 @@
+import React, { useEffect, useState } from 'react';
+import { Form } from 'semantic-ui-react';
+import { QueryClient, useQuery } from '@tanstack/react-query';
+import UtcDatePicker from '../../../wca/UtcDatePicker';
+import getCompetitionList from './api/getCompetitionList';
+import Loading from '../../../Requests/Loading';
+import Errored from '../../../Requests/Errored';
+
+const RUN_VALIDATORS_QUERY_CLIENT = new QueryClient();
+const MAX_COMPETITIONS_PER_QUERY = 50;
+
+export default function CompetitionRangeSelector({ range, setRange }) {
+ const [startDate, setStartDate] = useState(range?.startDate);
+ const [endDate, setEndDate] = useState(range?.endDate);
+
+ const enableCompetitionListFetch = Boolean(startDate && endDate);
+
+ const {
+ data: competitionList, isLoading, isError, refetch,
+ } = useQuery({
+ queryKey: ['competitionCountInRange'],
+ queryFn: () => getCompetitionList(startDate, endDate, MAX_COMPETITIONS_PER_QUERY),
+ enabled: enableCompetitionListFetch,
+ }, RUN_VALIDATORS_QUERY_CLIENT);
+
+ useEffect(() => {
+ setRange({ startDate, endDate });
+ if (enableCompetitionListFetch) {
+ refetch();
+ }
+ }, [startDate, endDate, setRange, enableCompetitionListFetch, refetch]);
+
+ return (
+ <>
+
+
+ {enableCompetitionListFetch && (
+ <>
+ {isLoading && ()}
+ {isError && }
+ {!isLoading && !isError && (
+
+ {`The checks will run for ${competitionList.length}${
+ competitionList.length >= MAX_COMPETITIONS_PER_QUERY ? '+' : ''
+ } competitions`}
+
+ )}
+ >
+ )}
+ >
+ );
+}
diff --git a/app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx b/app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
new file mode 100644
index 00000000000..0723ba79ba4
--- /dev/null
+++ b/app/webpacker/components/Panel/pages/RunValidatorsPage/RunValidatorsForm.jsx
@@ -0,0 +1,158 @@
+import React, { useState } from 'react';
+import {
+ Form, FormField, FormGroup, Header, Radio,
+} from 'semantic-ui-react';
+import { QueryClient, useQuery } from '@tanstack/react-query';
+import useInputState from '../../../../lib/hooks/useInputState';
+import { ALL_VALIDATORS, VALIDATORS_WITH_FIX } from '../../../../lib/wca-data.js.erb';
+import { IdWcaSearch } from '../../../SearchWidget/WcaSearch';
+import SEARCH_MODELS from '../../../SearchWidget/SearchModel';
+import CompetitionRangeSelector from './CompetitionRangeSelector';
+import useCheckboxState from '../../../../lib/hooks/useCheckboxState';
+import runValidatorsForCompetitionList from './api/runValidatorsForCompetitionList';
+import runValidatorsForCompetitionsInRange from './api/runValidatorsForCompetitionsInRange';
+import ValidationOutput from './ValidationOutput';
+
+const validatorNameReadable = (validatorName) => validatorName.split('::')[1];
+
+const VALIDATOR_OPTIONS = ALL_VALIDATORS.map((validator) => ({
+ key: validator,
+ text: validatorNameReadable(validator),
+ value: validator,
+}));
+
+const COMPETITION_SELECTION_OPTIONS_MAP = {
+ manual: {
+ key: 'manual',
+ text: 'Pick competition(s) manually',
+ },
+ range: {
+ key: 'range',
+ text: 'Competition between dates',
+ },
+};
+
+const COMPETITION_SELECTION_OPTIONS = [
+ COMPETITION_SELECTION_OPTIONS_MAP.manual.key,
+ COMPETITION_SELECTION_OPTIONS_MAP.range.key,
+];
+
+const RUN_VALIDATORS_QUERY_CLIENT = new QueryClient();
+
+export default function RunValidatorsForm({ competitionIds }) {
+ const [
+ selectedCompetitionSelectionOption,
+ setSelectedCompetitionSelectionOption,
+ ] = useInputState(COMPETITION_SELECTION_OPTIONS_MAP.manual.key);
+
+ const [selectedCompetitionIds, setSelectedCompetitionIds] = useInputState(competitionIds || []);
+ const [selectedCompetitionRange, setSelectedCompetitionRange] = useState();
+
+ const [selectedValidators, setSelectedValidators] = useInputState(ALL_VALIDATORS);
+ const [applyFixWhenPossible, setApplyFixWhenPossible] = useCheckboxState(false);
+
+ const runValidatorsForCompetitions = () => {
+ if (selectedCompetitionSelectionOption === COMPETITION_SELECTION_OPTIONS_MAP.manual.key) {
+ return runValidatorsForCompetitionList(
+ selectedCompetitionIds,
+ selectedValidators,
+ applyFixWhenPossible,
+ );
+ }
+ return runValidatorsForCompetitionsInRange(
+ selectedCompetitionRange,
+ selectedValidators,
+ applyFixWhenPossible,
+ );
+ };
+
+ const {
+ data: validationOutput, isFetching, isError, refetch: runValidators,
+ } = useQuery({
+ queryKey: ['competitionCountInRange'],
+ queryFn: runValidatorsForCompetitions,
+ enabled: false,
+ }, RUN_VALIDATORS_QUERY_CLIENT);
+
+ // enableCompetitionEditor says whether competition list editor should be enabled or not. If the
+ // list of competitions is passed as parameter, then the editor need not be shown.
+ const enableCompetitionEditor = !competitionIds;
+
+ // Competition name needs to be shown on output only when the script is not ran just for a single
+ // competition.
+ const showCompetitionNameOnOutput = !(
+ selectedCompetitionSelectionOption === COMPETITION_SELECTION_OPTIONS_MAP.manual.key
+ && selectedCompetitionIds.length === 1
+ );
+
+ return (
+ <>
+
+ )}
+ {(
+ selectedCompetitionSelectionOption === COMPETITION_SELECTION_OPTIONS_MAP.range.key
+ ) && (
+
+ )}
+ >
+ )}
+
+
+
+ Run Validators
+
+
+ >
+ );
+}
diff --git a/app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationListView.jsx b/app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationListView.jsx
new file mode 100644
index 00000000000..287be4757b8
--- /dev/null
+++ b/app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationListView.jsx
@@ -0,0 +1,56 @@
+import React, { useMemo } from 'react';
+import _ from 'lodash';
+import { Header, List, ListItem } from 'semantic-ui-react';
+import I18n from '../../../../lib/i18n';
+import { competitionUrl } from '../../../../lib/requests/routes.js.erb';
+
+const headingPrefixForType = (type) => {
+ switch (type) {
+ case 'info': return 'Information for';
+ case 'warning': return 'Warnings detected in';
+ case 'error': return 'Errors detected in';
+ default: return 'Unknown detected in';
+ }
+};
+
+export default function ValidationListView({ validations, showCompetitionNameOnOutput, type }) {
+ const listByGroup = useMemo(() => _.groupBy(validations, 'kind'), [validations]);
+
+ return (
+ <>
+ {Object.entries(listByGroup).map(([group, list]) => (
+ <>
+ {`${headingPrefixForType(type)} ${group}`}
+
+ {list.map((validationData) => (
+
+
+
+ ))}
+
+ >
+ ))}
+ >
+ );
+}
+
+function ValidationText({ validationData, group, showCompetitionNameOnOutput }) {
+ return (
+ <>
+ {showCompetitionNameOnOutput && (
+ <>
+ [
+
+ {validationData.competition_id}
+
+ {'] '}
+ >
+ )}
+ <>{I18n.t(`validators.${group}.${validationData.id}`, validationData.args)}>
+ >
+ );
+}
diff --git a/app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationOutput.jsx b/app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationOutput.jsx
new file mode 100644
index 00000000000..b28ca4a6f03
--- /dev/null
+++ b/app/webpacker/components/Panel/pages/RunValidatorsPage/ValidationOutput.jsx
@@ -0,0 +1,90 @@
+import React from 'react';
+import { Header, Message } from 'semantic-ui-react';
+import Loading from '../../../Requests/Loading';
+import Errored from '../../../Requests/Errored';
+import ValidationListView from './ValidationListView';
+
+export default function ValidationOutput({
+ validationOutput, isFetching, isError, showCompetitionNameOnOutput,
+}) {
+ if (isFetching) return ;
+ if (isError) return ;
+
+ if (!isFetching && !isError && !validationOutput) {
+ return (
+ Please run the validators to see the output.
+ );
+ }
+
+ return (
+ <>
+
+ {validationOutput.infos.length > 0 && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+ >
+ );
+}
+
+function ValidationErrorOutput({ validationOutput, showCompetitionNameOnOutput }) {
+ const hasResults = validationOutput.has_results;
+ const hasErrors = validationOutput.errors.length > 0;
+
+ if (!hasErrors) {
+ if (hasResults) {
+ return No error detected in the results.
;
+ }
+ return No results for the competition yet.
;
+ }
+
+ return (
+ <>
+ Please fix the errors below:
+
+ >
+ );
+}
+
+function ValidationWarningOutput({ validationOutput, showCompetitionNameOnOutput }) {
+ const hasResults = validationOutput.has_results;
+ const hasWarning = validationOutput.warnings.length > 0;
+
+ if (!hasWarning) {
+ if (hasResults) {
+ return No warning detected in the results.
;
+ }
+ return No results for the competition yet.
;
+ }
+
+ return (
+ <>
+ Please pay attention to the warnings below:
+
+ >
+ );
+}
diff --git a/app/webpacker/components/Panel/pages/RunValidatorsPage/api/getCompetitionList.js b/app/webpacker/components/Panel/pages/RunValidatorsPage/api/getCompetitionList.js
new file mode 100644
index 00000000000..f417a2da4b0
--- /dev/null
+++ b/app/webpacker/components/Panel/pages/RunValidatorsPage/api/getCompetitionList.js
@@ -0,0 +1,9 @@
+import { fetchJsonOrError } from '../../../../../lib/requests/fetchWithAuthenticityToken';
+import { apiV0Urls } from '../../../../../lib/requests/routes.js.erb';
+
+export default async function getCompetitionList(startDate, endDate, maxLimit) {
+ const { data } = await fetchJsonOrError(
+ `${apiV0Urls.competitions.listIndex}?start=${startDate}&end=${endDate}&per_page=${maxLimit}`,
+ );
+ return data;
+}
diff --git a/app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionList.js b/app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionList.js
new file mode 100644
index 00000000000..d840fc16075
--- /dev/null
+++ b/app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionList.js
@@ -0,0 +1,15 @@
+import { fetchJsonOrError } from '../../../../../lib/requests/fetchWithAuthenticityToken';
+import { actionUrls } from '../../../../../lib/requests/routes.js.erb';
+
+export default async function runValidatorsForCompetitionList(
+ competitionIds,
+ selectedValidators,
+ applyFixWhenPossible,
+) {
+ const { data } = await fetchJsonOrError(actionUrls.validators.forCompetitionList(
+ competitionIds,
+ selectedValidators,
+ applyFixWhenPossible,
+ ));
+ return data;
+}
diff --git a/app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionsInRange.js b/app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionsInRange.js
new file mode 100644
index 00000000000..f1801a44307
--- /dev/null
+++ b/app/webpacker/components/Panel/pages/RunValidatorsPage/api/runValidatorsForCompetitionsInRange.js
@@ -0,0 +1,15 @@
+import { fetchJsonOrError } from '../../../../../lib/requests/fetchWithAuthenticityToken';
+import { actionUrls } from '../../../../../lib/requests/routes.js.erb';
+
+export default async function runValidatorsForCompetitionsInRange(
+ competitionRange,
+ selectedValidators,
+ applyFixWhenPossible,
+) {
+ const { data } = await fetchJsonOrError(actionUrls.validators.forCompetitionsInRange(
+ JSON.stringify(competitionRange),
+ selectedValidators,
+ applyFixWhenPossible,
+ ));
+ return data;
+}
diff --git a/app/webpacker/lib/requests/routes.js.erb b/app/webpacker/lib/requests/routes.js.erb
index adb4593f92e..b8d1079fcae 100644
--- a/app/webpacker/lib/requests/routes.js.erb
+++ b/app/webpacker/lib/requests/routes.js.erb
@@ -276,6 +276,10 @@ export const actionUrls = {
users: {
anonymize: (userId) => `<%= CGI.unescape(Rails.application.routes.url_helpers.anonymize_user_path("${userId}")) %>`,
},
+ validators: {
+ forCompetitionList: (competitionIds, selectedValidators, applyFixWhenPossible) => `<%= CGI.unescape(Rails.application.routes.url_helpers.panel_validators_for_competition_list_path) %>?${jsonToQueryString({ competitionIds, selectedValidators, applyFixWhenPossible })}`,
+ forCompetitionsInRange: (competitionRange, selectedValidators, applyFixWhenPossible) => `<%= CGI.unescape(Rails.application.routes.url_helpers.panel_validators_for_competitions_in_range_path) %>?${jsonToQueryString({ competitionRange, selectedValidators, applyFixWhenPossible })}`,
+ },
}
export const userPreferencesRoute = `<%= CGI.unescape(Rails.application.routes.url_helpers.profile_edit_path)%>?section=preferences`;
@@ -308,8 +312,6 @@ export const paymentTicketUrl = (competitionId, donationIso) => `<%= CGI.unescap
export const serverStatusPageUrl = `<%= CGI.unescape(Rails.application.routes.url_helpers.server_status_path) %>`;
-export const runValidatorsUrl = `<%= CGI.unescape(Rails.application.routes.url_helpers.admin_check_results_path) %>`;
-
export const createNewComersUrl = `<%= CGI.unescape(Rails.application.routes.url_helpers.admin_finish_unfinished_persons_path) %>`;
export const checkRecordsUrl = `<%= CGI.unescape(Rails.application.routes.url_helpers.admin_check_regional_records_path) %>`;
diff --git a/app/webpacker/lib/wca-data.js.erb b/app/webpacker/lib/wca-data.js.erb
index 2615f4784b0..afc88072964 100644
--- a/app/webpacker/lib/wca-data.js.erb
+++ b/app/webpacker/lib/wca-data.js.erb
@@ -225,3 +225,7 @@ export const avatarImageTypes = <%= Rails.application.config.active_storage.web_
export const ticketTypes = <%= Ticket::TICKET_TYPES.to_json %>;
export const ticketStatuses = <%= Ticket::TICKET_TYPES.transform_values { |value| value.safe_constantize&.statuses }.to_json %>;
export const ticketLogActionTypes = <%= TicketLog.action_types.to_json %>;
+
+// ----- VALIDATORS -----
+export const ALL_VALIDATORS = <%= ResultsValidators::Utils::ALL_VALIDATORS.map(&:name) %>;
+export const VALIDATORS_WITH_FIX = <%= ResultsValidators::Utils::VALIDATORS_WITH_FIX.map(&:name) %>;
diff --git a/config/routes.rb b/config/routes.rb
index 8180c5b0545..c0101f1e32a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -112,7 +112,6 @@
# WRT views and action
get '/admin/upload-results' => "admin#new_results", as: :admin_upload_results_edit
get '/admin/check-existing-results' => "admin#check_competition_results", as: :admin_check_existing_results
- post '/admin/check-existing-results' => "admin#do_check_competition_results", as: :admin_run_validators
post '/admin/upload-json' => "admin#create_results", as: :admin_upload_results
post '/admin/clear-submission' => "admin#clear_results_submission", as: :clear_results_submission
get '/admin/import-results' => 'admin#import_results', as: :admin_import_results
@@ -190,10 +189,11 @@
scope 'panel' do
get 'staff' => 'panel#staff', as: :panel_staff
get 'generate_db_token' => 'panel#generate_db_token', as: :panel_generate_db_token
+ get 'validators_for_competition_list' => 'panel#validators_for_competition_list', as: :panel_validators_for_competition_list
+ get 'validators_for_competitions_in_range' => 'panel#validators_for_competitions_in_range', as: :panel_validators_for_competitions_in_range
end
get 'panel/:panel_id' => 'panel#index', as: :panel_index
scope 'panel-page' do
- get 'run-validators' => 'admin#check_results', as: :admin_check_results
get 'create-new-comers' => 'admin#finish_unfinished_persons', as: :admin_finish_unfinished_persons
get 'check-records' => 'admin#check_regional_records', as: :admin_check_regional_records
get 'compute-auxiliary-data' => 'admin#compute_auxiliary_data', as: :admin_compute_auxiliary_data
@@ -280,7 +280,6 @@
get '/admin/all-voters' => 'admin#all_voters', as: :eligible_voters
get '/admin/leader-senior-voters' => 'admin#leader_senior_voters', as: :leader_senior_voters
get '/admin/validation_competitions' => "admin#compute_validation_competitions"
- post '/admin/check_results' => 'admin#do_check_results'
post '/admin/merge_people' => 'admin#do_merge_people'
get '/admin/fix_results_selector' => 'admin#fix_results_selector', as: :admin_fix_results_ajax
get '/admin/person_data' => 'admin#person_data'