Skip to content

Commit

Permalink
feat: enhance samplers input-validation with isEmpty function
Browse files Browse the repository at this point in the history
  • Loading branch information
BenElferink committed Jan 8, 2025
1 parent 0168951 commit 9047f3f
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 16 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import { safeJsonParse } from '@/utils';
import React, { useEffect, useMemo } from 'react';
import { Input } from '@/reuseable-components';
import { isEmpty, safeJsonParse } from '@/utils';
import type { ErrorSamplerSpec } from '@/types';

type Props = {
Expand All @@ -24,11 +24,15 @@ const ErrorSampler: React.FC<Props> = ({ value, setValue, errorMessage }) => {
fallback_sampling_ratio: num,
};

const str = !!payload.fallback_sampling_ratio ? JSON.stringify(payload) : '';
const str = isEmpty(payload.fallback_sampling_ratio) ? '' : JSON.stringify(payload);

setValue(str);
};

useEffect(() => {
if (isEmpty(safeJsonParse(value, {}))) handleChange('0');
}, [value]);

return <Input title='Fallback sampling ratio' required type='number' min={MIN} max={MAX} value={mappedValue} onChange={({ target: { value: v } }) => handleChange(v)} errorMessage={errorMessage} />;
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo } from 'react';
import { safeJsonParse } from '@/utils';
import React, { useEffect, useMemo } from 'react';
import { Input } from '@/reuseable-components';
import { isEmpty, safeJsonParse } from '@/utils';
import type { ProbabilisticSamplerSpec } from '@/types';

type Props = {
Expand All @@ -24,11 +24,15 @@ const ProbabilisticSampler: React.FC<Props> = ({ value, setValue, errorMessage }
sampling_percentage: String(num),
};

const str = !!payload.sampling_percentage ? JSON.stringify(payload) : '';
const str = isEmpty(payload.sampling_percentage) ? '' : JSON.stringify(payload);

setValue(str);
};

useEffect(() => {
if (isEmpty(safeJsonParse(value, {}))) handleChange('0');
}, [value]);

return <Input title='Sampling percentage' required type='number' min={MIN} max={MAX} value={mappedValue} onChange={({ target: { value: v } }) => handleChange(v)} errorMessage={errorMessage} />;
};

Expand Down
12 changes: 5 additions & 7 deletions frontend/webapp/hooks/actions/useActionFormData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useGenericForm } from '@/hooks';
import { FORM_ALERTS, safeJsonParse } from '@/utils';
import { DrawerItem, useNotificationStore } from '@/store';
import { FORM_ALERTS, isEmpty, safeJsonParse } from '@/utils';
import { ActionsType, LatencySamplerSpec, NOTIFICATION_TYPE, type ActionDataParsed, type ActionInput } from '@/types';

const INITIAL: ActionInput = {
Expand All @@ -17,6 +17,8 @@ export function useActionFormData() {
const { addNotification } = useNotificationStore();
const { formData, formErrors, handleFormChange, handleErrorChange, resetFormData } = useGenericForm<ActionInput>(INITIAL);

console.log('formData', formData);

const validateForm = (params?: { withAlert?: boolean; alertTitle?: string }) => {
const errors = {};
let ok = true;
Expand All @@ -25,15 +27,11 @@ export function useActionFormData() {
switch (k) {
case 'type':
case 'signals':
if (Array.isArray(v) ? !v.length : !v) {
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
}
if (isEmpty(v)) errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
break;

case 'details':
if (Array.isArray(v) ? !v.length : !v) {
errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
}
if (isEmpty(v)) errors[k] = FORM_ALERTS.FIELD_IS_REQUIRED;
if (formData.type === ActionsType.LATENCY_SAMPLER) {
(safeJsonParse(v as string, { endpoints_filters: [] }) as LatencySamplerSpec).endpoints_filters.forEach((endpoint) => {
if (endpoint.http_route.charAt(0) !== '/') {
Expand Down
7 changes: 4 additions & 3 deletions frontend/webapp/reuseable-components/input-table/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { useState, useEffect, useRef, useMemo, type KeyboardEventHandler
import styled from 'styled-components';
import { PlusIcon, TrashIcon } from '@/assets';
import { Button, FieldError, FieldLabel, Input, Text } from '@/reuseable-components';
import { isEmpty } from '@/utils';

type Row = {
[key: string]: any;
Expand Down Expand Up @@ -70,7 +71,7 @@ export const InputTable: React.FC<Props> = ({ columns, initialValues = [], value
}, []);

// Filter out rows where either key or value is empty
const validRows = useMemo(() => rows.filter((row) => !Object.values(row).filter((val) => !val).length), [rows]);
const validRows = useMemo(() => rows.filter((row) => !Object.values(row).filter((val) => isEmpty(val)).length), [rows]);
const recordedRows = useRef(JSON.stringify(validRows));

useEffect(() => {
Expand Down Expand Up @@ -140,9 +141,9 @@ export const InputTable: React.FC<Props> = ({ columns, initialValues = [], value
placeholder={placeholder}
value={value}
onChange={({ target: { value: val } }) => handleChange(keyName, type === 'number' ? Number(val) : val, idx)}
autoFocus={!value && rows.length > 1 && idx === rows.length - 1 && innerIdx === 0}
autoFocus={isEmpty(value) && rows.length > 1 && idx === rows.length - 1 && innerIdx === 0}
style={{ maxWidth, paddingLeft: 10 }}
hasError={!!errorMessage && (!required || (required && !value))}
hasError={!!errorMessage && (!required || (required && isEmpty(value)))}
/>
</td>
);
Expand Down
1 change: 1 addition & 0 deletions frontend/webapp/utils/functions/resolvers/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './compare-condition';
export * from './get-value-for-range';
export * from './is-emtpy';
12 changes: 12 additions & 0 deletions frontend/webapp/utils/functions/resolvers/is-emtpy/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Sometimes we need to allow "zero" values, and a simple "!val" check would result in false positives.
// This function is a strict check for empty values, permitting values like "0" and "false".

export const isEmpty = (val: any) => {
if (Array.isArray(val)) {
return !val.length;
} else if (typeof val === 'object') {
return !Object.keys(val).length;
} else {
return [undefined, null, ''].includes(val);
}
};

0 comments on commit 9047f3f

Please sign in to comment.