UX: indicate that a search field is actually a regex, add feedback to the filterview

This commit is contained in:
Pieter Vander Vennet 2024-09-17 02:51:02 +02:00
parent 5da63bf83a
commit ebe7ff85f8
5 changed files with 39 additions and 7 deletions

View file

@ -850,6 +850,9 @@
"description": "a positive, whole number", "description": "a positive, whole number",
"noZero": "Zero is not allowed" "noZero": "Zero is not allowed"
}, },
"regex": {
"description": "a regular expression"
},
"slope": { "slope": {
"inputExplanation": "Place your phone on the ground with the top side of your phone pointing towards the top of the slope.", "inputExplanation": "Place your phone on the ground with the top side of your phone pointing towards the top of the slope.",
"inputIncorrect": "For correct measurements, make sure the arrow is within the green area." "inputIncorrect": "For correct measurements, make sure the arrow is within the green area."

View file

@ -60,7 +60,7 @@ export default class FilterConfig {
} }
const fields: { name: string; type: ValidatorType }[] = (option.fields ?? []).map((f, i) => { const fields: { name: string; type: ValidatorType }[] = (option.fields ?? []).map((f, i) => {
const type = <ValidatorType> f.type ?? "string" const type = <ValidatorType> f.type ?? "regex"
if(Validators.availableTypes.indexOf(type) < 0){ if(Validators.availableTypes.indexOf(type) < 0){
throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(type, <any>Validators.availableTypes, x => x).slice(0, 3)}` throw `Invalid filter: type is not a valid validator. Did you mean one of ${Utils.sortedByLevenshteinDistance(type, <any>Validators.availableTypes, x => x).slice(0, 3)}`
} }

View file

@ -8,6 +8,8 @@
import { Utils } from "../../Utils" import { Utils } from "../../Utils"
import type { ValidatorType } from "../InputElement/Validators" import type { ValidatorType } from "../InputElement/Validators"
import InputHelper from "../InputElement/InputHelper.svelte" import InputHelper from "../InputElement/InputHelper.svelte"
import { Translation } from "../i18n/Translation"
import Tr from "../Base/Tr.svelte"
export let filteredLayer: FilteredLayer export let filteredLayer: FilteredLayer
export let option: FilterConfigOption export let option: FilterConfigOption
@ -47,9 +49,10 @@
onDestroy( onDestroy(
src.stabilized(200).addCallback(() => { src.stabilized(200).addCallback(() => {
setFields() setFields()
}), })
) )
} }
let feedback: UIEventSource<Translation> = new UIEventSource<Translation>(undefined)
</script> </script>
<div class="low-interaction p-1 rounded-2xl px-3" class:interactive={$firstValue?.length > 0}> <div class="low-interaction p-1 rounded-2xl px-3" class:interactive={$firstValue?.length > 0}>
@ -58,11 +61,15 @@
<!-- This is a field! --> <!-- This is a field! -->
<span class="mx-1"> <span class="mx-1">
<InputHelper value={fieldValues[part["subs"]]} type={fieldTypes[part["subs"]]}> <InputHelper value={fieldValues[part["subs"]]} type={fieldTypes[part["subs"]]}>
<ValidatedInput slot="fallback" value={fieldValues[part["subs"]]} type={fieldTypes[part["subs"]]} /> <ValidatedInput slot="fallback" value={fieldValues[part["subs"]]} type={fieldTypes[part["subs"]]}
{feedback} />
</InputHelper> </InputHelper>
</span> </span>
{:else} {:else}
{@html part["message"]} {@html part["message"]}
{/if} {/if}
{/each} {/each}
{#if $feedback}
<Tr cls="alert" t={$feedback}/>
{/if}
</div> </div>

View file

@ -15,9 +15,6 @@ import UrlValidator from "./Validators/UrlValidator"
import PhoneValidator from "./Validators/PhoneValidator" import PhoneValidator from "./Validators/PhoneValidator"
import OpeningHoursValidator from "./Validators/OpeningHoursValidator" import OpeningHoursValidator from "./Validators/OpeningHoursValidator"
import ColorValidator from "./Validators/ColorValidator" import ColorValidator from "./Validators/ColorValidator"
import BaseUIElement from "../BaseUIElement"
import Combine from "../Base/Combine"
import Title from "../Base/Title"
import SimpleTagValidator from "./Validators/SimpleTagValidator" import SimpleTagValidator from "./Validators/SimpleTagValidator"
import ImageUrlValidator from "./Validators/ImageUrlValidator" import ImageUrlValidator from "./Validators/ImageUrlValidator"
import TagKeyValidator from "./Validators/TagKeyValidator" import TagKeyValidator from "./Validators/TagKeyValidator"
@ -30,6 +27,7 @@ import SlopeValidator from "./Validators/SlopeValidator"
import VeloparkValidator from "./Validators/VeloparkValidator" import VeloparkValidator from "./Validators/VeloparkValidator"
import NameSuggestionIndexValidator from "./Validators/NameSuggestionIndexValidator" import NameSuggestionIndexValidator from "./Validators/NameSuggestionIndexValidator"
import CurrencyValidator from "./Validators/CurrencyValidator" import CurrencyValidator from "./Validators/CurrencyValidator"
import RegexValidator from "./Validators/RegexValidator"
export type ValidatorType = (typeof Validators.availableTypes)[number] export type ValidatorType = (typeof Validators.availableTypes)[number]
@ -64,6 +62,7 @@ export default class Validators {
"velopark", "velopark",
"nsi", "nsi",
"currency", "currency",
"regex"
] as const ] as const
public static readonly AllValidators: ReadonlyArray<Validator> = [ public static readonly AllValidators: ReadonlyArray<Validator> = [
@ -95,6 +94,7 @@ export default class Validators {
new VeloparkValidator(), new VeloparkValidator(),
new NameSuggestionIndexValidator(), new NameSuggestionIndexValidator(),
new CurrencyValidator(), new CurrencyValidator(),
new RegexValidator()
] ]
private static _byType = Validators._byTypeConstructor() private static _byType = Validators._byTypeConstructor()

View file

@ -0,0 +1,22 @@
import StringValidator from "./StringValidator"
import { s } from "vitest/dist/env-afee91f0"
import { Translation } from "../../i18n/Translation"
import Translations from "../../i18n/Translations"
export default class RegexValidator extends StringValidator{
constructor() {
super("regex", "Validates a regex")
}
getFeedback(s: string): Translation | undefined {
try{
new RegExp(s)
}catch (e) {
return Translations.T("Not a valid Regex: "+e)
}
}
isValid(s: string): boolean {
return this.getFeedback(s) === undefined
}
}