src/components/Search/loader.ts (93 lines of code) (raw):

import { repoMap, frameworks } from '../../common/constants'; import { memoizedFetchRevisionForRepository } from '../../logic/treeherder'; import { Changeset, Repository } from '../../types/state'; import { Framework } from '../../types/types'; const DEFAULT_VALUES = { newRev: null, newRevInfo: null, newRepo: 'try' as Repository['name'], frameworkId: 1 as Framework['id'], frameworkName: 'talos' as Framework['name'], }; // This function checks and sanitizes the input values, then returns values that // we can then use in the rest of the application. function checkValues({ newRev, newRepo, frameworkName, }: { newRev: string | null; newRepo: Repository['name'] | null; frameworkName: Framework['name'] | null; }): null | { newRev: string; newRepo: Repository['name']; frameworkId: Framework['id']; frameworkName: Framework['name']; } { if (newRev === null || newRepo === null) { return null; } const validRepoValues = Object.values(repoMap); if (!validRepoValues.includes(newRepo)) { console.warn(`The repository ${newRepo} wasn't found in our list.`); return null; } if (frameworkName === null) { frameworkName = DEFAULT_VALUES.frameworkName; } let frameworkId = frameworks.find( (entry) => entry.name === frameworkName, )?.id; if (frameworkId === undefined) { // Default to talos if the entry wasn't found. console.warn( `The framework entry for ${frameworkName} wasn't found, defaulting to talos.`, ); frameworkId = DEFAULT_VALUES.frameworkId; frameworkName = DEFAULT_VALUES.frameworkName; } return { newRev, newRepo, frameworkId, frameworkName, }; } // This function is responsible for fetching the data from the URL. It's called // by React Router DOM when the compare-results path is requested. // It uses the URL parameters as inputs, and returns all the fetched data to the // React components through React Router's useLoaderData hook. export async function loader({ request }: { request: Request }) { const url = new URL(request.url); const newRevFromUrl = url.searchParams.get('newRev'); const newRepoFromUrl = url.searchParams.get('newRepo') as | Repository['name'] | null; const frameworkFromUrl = url.searchParams.get('frameworkName') as | Framework['name'] | null; const checkedValues = checkValues({ newRev: newRevFromUrl, newRepo: newRepoFromUrl, frameworkName: frameworkFromUrl, }); if (!checkedValues) { return DEFAULT_VALUES; } const { newRev, newRepo, frameworkId, frameworkName } = checkedValues; const newRevInfo = await memoizedFetchRevisionForRepository({ repository: newRepo, hash: newRev, }); if (!newRevInfo) { // The search returned no result. return DEFAULT_VALUES; } return { newRev, newRevInfo, newRepo, frameworkId, frameworkName, }; } // Be explicit with the returned type to control it better than if we were // inferring it. export type LoaderReturnValue = { newRev: string; newRevInfo: Changeset; newRepo: Repository['name']; frameworkId: Framework['id']; frameworkName: Framework['name']; };