mirror of
https://github.com/mountain-loop/yaak.git
synced 2026-04-19 23:41:18 +02:00
Better Header validation
This commit is contained in:
@@ -18,6 +18,7 @@ export function HeaderEditor({ headers, onChange }: Props) {
|
|||||||
<PairEditor
|
<PairEditor
|
||||||
pairs={headers}
|
pairs={headers}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
nameValidate={validateHttpHeader}
|
||||||
nameAutocomplete={nameAutocomplete}
|
nameAutocomplete={nameAutocomplete}
|
||||||
valueAutocomplete={valueAutocomplete}
|
valueAutocomplete={valueAutocomplete}
|
||||||
namePlaceholder="Header-Name"
|
namePlaceholder="Header-Name"
|
||||||
@@ -50,3 +51,11 @@ const nameAutocomplete: PairEditorProps['nameAutocomplete'] = {
|
|||||||
minMatch: MIN_MATCH,
|
minMatch: MIN_MATCH,
|
||||||
options: headerNames.map((t, i) => ({ label: t, type: 'constant', boost: 99 - i })),
|
options: headerNames.map((t, i) => ({ label: t, type: 'constant', boost: 99 - i })),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const validateHttpHeader = (v: string) => {
|
||||||
|
if (v === '') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return v.match(/^[a-zA-Z0-9-_]+$/) !== null;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
import { useMemo, useState } from 'react';
|
|
||||||
import type { HTMLAttributes, ReactNode } from 'react';
|
import type { HTMLAttributes, ReactNode } from 'react';
|
||||||
|
import { useMemo, useState } from 'react';
|
||||||
import type { EditorProps } from './Editor';
|
import type { EditorProps } from './Editor';
|
||||||
import { Editor } from './Editor';
|
import { Editor } from './Editor';
|
||||||
import { HStack, VStack } from './Stacks';
|
import { HStack, VStack } from './Stacks';
|
||||||
|
|
||||||
type Props = Omit<HTMLAttributes<HTMLInputElement>, 'onChange' | 'onFocus'> &
|
export type InputProps = Omit<HTMLAttributes<HTMLInputElement>, 'onChange' | 'onFocus'> &
|
||||||
Pick<EditorProps, 'contentType' | 'useTemplating' | 'autocomplete'> & {
|
Pick<EditorProps, 'contentType' | 'useTemplating' | 'autocomplete'> & {
|
||||||
name: string;
|
name: string;
|
||||||
label: string;
|
label: string;
|
||||||
@@ -41,7 +41,7 @@ export function Input({
|
|||||||
validate,
|
validate,
|
||||||
require,
|
require,
|
||||||
...props
|
...props
|
||||||
}: Props) {
|
}: InputProps) {
|
||||||
const [currentValue, setCurrentValue] = useState(defaultValue ?? '');
|
const [currentValue, setCurrentValue] = useState(defaultValue ?? '');
|
||||||
const id = `input-${name}`;
|
const id = `input-${name}`;
|
||||||
const inputClassName = classnames(
|
const inputClassName = classnames(
|
||||||
@@ -80,7 +80,7 @@ export function Input({
|
|||||||
containerClassName,
|
containerClassName,
|
||||||
'relative w-full rounded-md text-gray-900',
|
'relative w-full rounded-md text-gray-900',
|
||||||
'border border-gray-200 focus-within:border-focus',
|
'border border-gray-200 focus-within:border-focus',
|
||||||
!isValid && 'border-invalid',
|
!isValid && '!border-invalid',
|
||||||
size === 'md' && 'h-md',
|
size === 'md' && 'h-md',
|
||||||
size === 'sm' && 'h-sm',
|
size === 'sm' && 'h-sm',
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import { Checkbox } from './Checkbox';
|
|||||||
import type { GenericCompletionConfig } from './Editor/genericCompletion';
|
import type { GenericCompletionConfig } from './Editor/genericCompletion';
|
||||||
import { Icon } from './Icon';
|
import { Icon } from './Icon';
|
||||||
import { IconButton } from './IconButton';
|
import { IconButton } from './IconButton';
|
||||||
|
import type { InputProps } from './Input';
|
||||||
import { Input } from './Input';
|
import { Input } from './Input';
|
||||||
import { HStack } from './Stacks';
|
|
||||||
|
|
||||||
export type PairEditorProps = {
|
export type PairEditorProps = {
|
||||||
pairs: Pair[];
|
pairs: Pair[];
|
||||||
@@ -21,6 +21,8 @@ export type PairEditorProps = {
|
|||||||
valuePlaceholder?: string;
|
valuePlaceholder?: string;
|
||||||
nameAutocomplete?: GenericCompletionConfig;
|
nameAutocomplete?: GenericCompletionConfig;
|
||||||
valueAutocomplete?: (name: string) => GenericCompletionConfig | undefined;
|
valueAutocomplete?: (name: string) => GenericCompletionConfig | undefined;
|
||||||
|
nameValidate?: InputProps['validate'];
|
||||||
|
valueValidate?: InputProps['validate'];
|
||||||
};
|
};
|
||||||
|
|
||||||
type Pair = {
|
type Pair = {
|
||||||
@@ -40,6 +42,8 @@ export const PairEditor = memo(function PairEditor({
|
|||||||
valueAutocomplete,
|
valueAutocomplete,
|
||||||
namePlaceholder,
|
namePlaceholder,
|
||||||
valuePlaceholder,
|
valuePlaceholder,
|
||||||
|
nameValidate,
|
||||||
|
valueValidate,
|
||||||
className,
|
className,
|
||||||
onChange,
|
onChange,
|
||||||
}: PairEditorProps) {
|
}: PairEditorProps) {
|
||||||
@@ -140,6 +144,8 @@ export const PairEditor = memo(function PairEditor({
|
|||||||
valueAutocomplete={valueAutocomplete}
|
valueAutocomplete={valueAutocomplete}
|
||||||
namePlaceholder={namePlaceholder}
|
namePlaceholder={namePlaceholder}
|
||||||
valuePlaceholder={valuePlaceholder}
|
valuePlaceholder={valuePlaceholder}
|
||||||
|
nameValidate={nameValidate}
|
||||||
|
valueValidate={valueValidate}
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onFocus={handleFocus}
|
onFocus={handleFocus}
|
||||||
onDelete={isLast ? undefined : handleDelete}
|
onDelete={isLast ? undefined : handleDelete}
|
||||||
@@ -168,7 +174,12 @@ type FormRowProps = {
|
|||||||
isLast?: boolean;
|
isLast?: boolean;
|
||||||
} & Pick<
|
} & Pick<
|
||||||
PairEditorProps,
|
PairEditorProps,
|
||||||
'nameAutocomplete' | 'valueAutocomplete' | 'namePlaceholder' | 'valuePlaceholder'
|
| 'nameAutocomplete'
|
||||||
|
| 'valueAutocomplete'
|
||||||
|
| 'namePlaceholder'
|
||||||
|
| 'valuePlaceholder'
|
||||||
|
| 'nameValidate'
|
||||||
|
| 'valueValidate'
|
||||||
>;
|
>;
|
||||||
|
|
||||||
const FormRow = memo(function FormRow({
|
const FormRow = memo(function FormRow({
|
||||||
@@ -183,6 +194,8 @@ const FormRow = memo(function FormRow({
|
|||||||
valueAutocomplete,
|
valueAutocomplete,
|
||||||
namePlaceholder,
|
namePlaceholder,
|
||||||
valuePlaceholder,
|
valuePlaceholder,
|
||||||
|
nameValidate,
|
||||||
|
valueValidate,
|
||||||
}: FormRowProps) {
|
}: FormRowProps) {
|
||||||
const { id } = pairContainer;
|
const { id } = pairContainer;
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
@@ -272,6 +285,7 @@ const FormRow = memo(function FormRow({
|
|||||||
hideLabel
|
hideLabel
|
||||||
size="sm"
|
size="sm"
|
||||||
require={!isLast && !!pairContainer.pair.enabled && !!pairContainer.pair.value}
|
require={!isLast && !!pairContainer.pair.enabled && !!pairContainer.pair.value}
|
||||||
|
validate={nameValidate}
|
||||||
useTemplating
|
useTemplating
|
||||||
containerClassName={classnames(isLast && 'border-dashed')}
|
containerClassName={classnames(isLast && 'border-dashed')}
|
||||||
defaultValue={pairContainer.pair.name}
|
defaultValue={pairContainer.pair.name}
|
||||||
@@ -286,6 +300,7 @@ const FormRow = memo(function FormRow({
|
|||||||
hideLabel
|
hideLabel
|
||||||
size="sm"
|
size="sm"
|
||||||
containerClassName={classnames(isLast && 'border-dashed')}
|
containerClassName={classnames(isLast && 'border-dashed')}
|
||||||
|
validate={valueValidate}
|
||||||
defaultValue={pairContainer.pair.value}
|
defaultValue={pairContainer.pair.value}
|
||||||
label="Value"
|
label="Value"
|
||||||
name="value"
|
name="value"
|
||||||
|
|||||||
Reference in New Issue
Block a user