diff --git a/frontend/src/ts/elements/input-validation.ts b/frontend/src/ts/elements/input-validation.ts index 21499aed6..73a595679 100644 --- a/frontend/src/ts/elements/input-validation.ts +++ b/frontend/src/ts/elements/input-validation.ts @@ -145,6 +145,7 @@ export type ValidationOptions = (T extends string export type ValidatedHtmlInputElement = HTMLInputElement & { isValid: () => boolean | undefined; + setValue: (val: string | null) => void; }; /** * adds an 'InputIndicator` to the given `inputElement` and updates its status depending on the given validation @@ -197,6 +198,15 @@ export function validateWithIndicator( const result = inputElement as ValidatedHtmlInputElement; result.isValid = () => isValid; + result.setValue = (val: string | null) => { + inputElement.value = val ?? ""; + if (val === null) { + isValid = undefined; + indicator.hide(); + } else { + inputElement.dispatchEvent(new Event("input")); + } + }; return result; } diff --git a/frontend/src/ts/modals/edit-preset.ts b/frontend/src/ts/modals/edit-preset.ts index 29b213bf1..6f9cdd91a 100644 --- a/frontend/src/ts/modals/edit-preset.ts +++ b/frontend/src/ts/modals/edit-preset.ts @@ -6,7 +6,11 @@ import * as Settings from "../pages/settings"; import * as Notifications from "../elements/notifications"; import * as ConnectionState from "../states/connection"; import AnimatedModal from "../utils/animated-modal"; -import { PresetType, PresetTypeSchema } from "@monkeytype/schemas/presets"; +import { + PresetNameSchema, + PresetType, + PresetTypeSchema, +} from "@monkeytype/schemas/presets"; import { getPreset } from "../controllers/preset-controller"; import { ConfigGroupName, @@ -17,6 +21,10 @@ import { } from "@monkeytype/schemas/configs"; import { getDefaultConfig } from "../constants/default-config"; import { SnapshotPreset } from "../constants/default-snapshot"; +import { + ValidatedHtmlInputElement, + validateWithIndicator, +} from "../elements/input-validation"; const state = { presetType: "full" as PresetType, @@ -26,6 +34,8 @@ const state = { setPresetToCurrent: false, }; +let presetNameEl: ValidatedHtmlInputElement | null = null; + export function show(action: string, id?: string, name?: string): void { if (!ConnectionState.get()) { Notifications.add("You are offline", 0, { @@ -39,11 +49,22 @@ export function show(action: string, id?: string, name?: string): void { beforeAnimation: async () => { $("#editPresetModal .modal .text").addClass("hidden"); addCheckBoxes(); + if (!presetNameEl) { + presetNameEl = validateWithIndicator( + document.querySelector( + "#editPresetModal .modal input" + ) as HTMLInputElement, + { + schema: PresetNameSchema, + } + ); + } if (action === "add") { $("#editPresetModal .modal").attr("data-action", "add"); $("#editPresetModal .modal .popupTitle").html("Add new preset"); $("#editPresetModal .modal .submit").html(`add`); - $("#editPresetModal .modal input").val(""); + presetNameEl?.setValue(null); + presetNameEl?.parentElement?.classList.remove("hidden"); $("#editPresetModal .modal input").removeClass("hidden"); $( "#editPresetModal .modal label.changePresetToCurrentCheckbox" @@ -57,7 +78,9 @@ export function show(action: string, id?: string, name?: string): void { $("#editPresetModal .modal").attr("data-preset-id", id); $("#editPresetModal .modal .popupTitle").html("Edit preset"); $("#editPresetModal .modal .submit").html(`save`); - $("#editPresetModal .modal input").val(name); + presetNameEl?.setValue(name); + presetNameEl?.parentElement?.classList.remove("hidden"); + $("#editPresetModal .modal input").removeClass("hidden"); $( "#editPresetModal .modal label.changePresetToCurrentCheckbox" @@ -85,6 +108,7 @@ export function show(action: string, id?: string, name?: string): void { $("#editPresetModal .modal .inputs").addClass("hidden"); $("#editPresetModal .modal .presetType").addClass("hidden"); $("#editPresetModal .modal .presetNameTitle").addClass("hidden"); + presetNameEl?.parentElement?.classList.add("hidden"); } updateUI(); }, @@ -238,6 +262,11 @@ async function apply(): Promise { return; } + if (presetNameEl?.isValid() === false) { + Notifications.add("Preset name is not valid", 0); + return; + } + hide(); Loader.show();