Hotfix location in pipeline search (#108)
* feat(shared): centralize supported country list and source-country rules * feat(orchestrator): add country selector and UK-only source gating in automatic run modal * feat(orchestrator): persist country selection and run only compatible extractors * fix(pipeline): enforce country-source compatibility during discovery * test(orchestrator): cover country-based source gating and pipeline enforcement * formatting * test fix * lint * comments * prevent auto focus grab * verification * command and popover * make sure scroll is working
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
export * from "./location-support";
|
||||
export * from "./types";
|
||||
export * from "./utils/type-conversion";
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
formatCountryLabel,
|
||||
getCompatibleSourcesForCountry,
|
||||
isSourceAllowedForCountry,
|
||||
isUkCountry,
|
||||
normalizeCountryKey,
|
||||
SUPPORTED_COUNTRY_KEYS,
|
||||
} from "./location-support";
|
||||
|
||||
describe("location-support", () => {
|
||||
it("normalizes country aliases", () => {
|
||||
expect(normalizeCountryKey("UK")).toBe("united kingdom");
|
||||
expect(normalizeCountryKey("us")).toBe("united states");
|
||||
expect(normalizeCountryKey("usa")).toBe("united states");
|
||||
expect(normalizeCountryKey("czech republic")).toBe("czechia");
|
||||
});
|
||||
|
||||
it("formats country labels", () => {
|
||||
expect(formatCountryLabel("united kingdom")).toBe("United Kingdom");
|
||||
expect(formatCountryLabel("usa/ca")).toBe("USA/CA");
|
||||
expect(formatCountryLabel("south korea")).toBe("South Korea");
|
||||
});
|
||||
|
||||
it("keeps supported country keys unique and canonical", () => {
|
||||
expect(SUPPORTED_COUNTRY_KEYS).toContain("united kingdom");
|
||||
expect(SUPPORTED_COUNTRY_KEYS).toContain("united states");
|
||||
expect(SUPPORTED_COUNTRY_KEYS).toContain("worldwide");
|
||||
expect(SUPPORTED_COUNTRY_KEYS).not.toContain("uk");
|
||||
expect(SUPPORTED_COUNTRY_KEYS).not.toContain("us");
|
||||
});
|
||||
|
||||
it("treats only united kingdom as UK country", () => {
|
||||
expect(isUkCountry("united kingdom")).toBe(true);
|
||||
expect(isUkCountry("UK")).toBe(true);
|
||||
expect(isUkCountry("worldwide")).toBe(false);
|
||||
expect(isUkCountry("usa/ca")).toBe(false);
|
||||
expect(isUkCountry("united states")).toBe(false);
|
||||
});
|
||||
|
||||
it("applies source compatibility rules by country", () => {
|
||||
expect(isSourceAllowedForCountry("gradcracker", "united kingdom")).toBe(
|
||||
true,
|
||||
);
|
||||
expect(isSourceAllowedForCountry("ukvisajobs", "uk")).toBe(true);
|
||||
expect(isSourceAllowedForCountry("gradcracker", "united states")).toBe(
|
||||
false,
|
||||
);
|
||||
expect(isSourceAllowedForCountry("ukvisajobs", "worldwide")).toBe(false);
|
||||
expect(isSourceAllowedForCountry("indeed", "united states")).toBe(true);
|
||||
expect(isSourceAllowedForCountry("linkedin", "worldwide")).toBe(true);
|
||||
});
|
||||
|
||||
it("filters incompatible sources while preserving compatible order", () => {
|
||||
expect(
|
||||
getCompatibleSourcesForCountry(
|
||||
["gradcracker", "indeed", "ukvisajobs", "linkedin"],
|
||||
"united states",
|
||||
),
|
||||
).toEqual(["indeed", "linkedin"]);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,141 @@
|
||||
import type { JobSource } from "./types";
|
||||
|
||||
const COUNTRY_ALIASES: Record<string, string> = {
|
||||
uk: "united kingdom",
|
||||
us: "united states",
|
||||
usa: "united states",
|
||||
türkiye: "turkey",
|
||||
"czech republic": "czechia",
|
||||
};
|
||||
|
||||
const COUNTRY_LABELS: Record<string, string> = {
|
||||
"united kingdom": "United Kingdom",
|
||||
"united states": "United States",
|
||||
"usa/ca": "USA/CA",
|
||||
turkey: "Turkey",
|
||||
czechia: "Czechia",
|
||||
};
|
||||
|
||||
// Keep this list aligned with the JobSpy supported country inputs.
|
||||
export const SUPPORTED_COUNTRY_INPUTS = [
|
||||
"argentina",
|
||||
"australia",
|
||||
"austria",
|
||||
"bahrain",
|
||||
"bangladesh",
|
||||
"belgium",
|
||||
"bulgaria",
|
||||
"brazil",
|
||||
"canada",
|
||||
"chile",
|
||||
"china",
|
||||
"colombia",
|
||||
"costa rica",
|
||||
"croatia",
|
||||
"cyprus",
|
||||
"czech republic",
|
||||
"czechia",
|
||||
"denmark",
|
||||
"ecuador",
|
||||
"egypt",
|
||||
"estonia",
|
||||
"finland",
|
||||
"france",
|
||||
"germany",
|
||||
"greece",
|
||||
"hong kong",
|
||||
"hungary",
|
||||
"india",
|
||||
"indonesia",
|
||||
"ireland",
|
||||
"israel",
|
||||
"italy",
|
||||
"japan",
|
||||
"kuwait",
|
||||
"latvia",
|
||||
"lithuania",
|
||||
"luxembourg",
|
||||
"malaysia",
|
||||
"malta",
|
||||
"mexico",
|
||||
"morocco",
|
||||
"netherlands",
|
||||
"new zealand",
|
||||
"nigeria",
|
||||
"norway",
|
||||
"oman",
|
||||
"pakistan",
|
||||
"panama",
|
||||
"peru",
|
||||
"philippines",
|
||||
"poland",
|
||||
"portugal",
|
||||
"qatar",
|
||||
"romania",
|
||||
"saudi arabia",
|
||||
"singapore",
|
||||
"slovakia",
|
||||
"slovenia",
|
||||
"south africa",
|
||||
"south korea",
|
||||
"spain",
|
||||
"sweden",
|
||||
"switzerland",
|
||||
"taiwan",
|
||||
"thailand",
|
||||
"türkiye",
|
||||
"turkey",
|
||||
"ukraine",
|
||||
"united arab emirates",
|
||||
"uk",
|
||||
"united kingdom",
|
||||
"usa",
|
||||
"us",
|
||||
"united states",
|
||||
"uruguay",
|
||||
"venezuela",
|
||||
"vietnam",
|
||||
"usa/ca",
|
||||
"worldwide",
|
||||
] as const;
|
||||
|
||||
const UK_ONLY_SOURCES = new Set<JobSource>(["gradcracker", "ukvisajobs"]);
|
||||
|
||||
export function normalizeCountryKey(value: string | null | undefined): string {
|
||||
const normalized = value?.trim().toLowerCase() ?? "";
|
||||
return COUNTRY_ALIASES[normalized] ?? normalized;
|
||||
}
|
||||
|
||||
export function formatCountryLabel(value: string): string {
|
||||
const normalized = normalizeCountryKey(value);
|
||||
if (!normalized) return "";
|
||||
return (
|
||||
COUNTRY_LABELS[normalized] ||
|
||||
normalized.replace(/\b\w/g, (char) => char.toUpperCase())
|
||||
);
|
||||
}
|
||||
|
||||
export const SUPPORTED_COUNTRY_KEYS = Array.from(
|
||||
new Set(
|
||||
SUPPORTED_COUNTRY_INPUTS.map((country) => normalizeCountryKey(country)),
|
||||
),
|
||||
).filter(Boolean);
|
||||
|
||||
export function isUkCountry(country: string | null | undefined): boolean {
|
||||
return normalizeCountryKey(country) === "united kingdom";
|
||||
}
|
||||
|
||||
export function isSourceAllowedForCountry(
|
||||
source: JobSource,
|
||||
country: string | null | undefined,
|
||||
): boolean {
|
||||
if (!UK_ONLY_SOURCES.has(source)) return true;
|
||||
return isUkCountry(country);
|
||||
}
|
||||
|
||||
export function getCompatibleSourcesForCountry(
|
||||
sources: JobSource[],
|
||||
country: string | null | undefined,
|
||||
): JobSource[] {
|
||||
return sources.filter((source) => isSourceAllowedForCountry(source, country));
|
||||
}
|
||||
Reference in New Issue
Block a user