Skip to content

Commit

Permalink
[GEN-2181]: enhance samplers input-validation with isEmpty function (#…
Browse files Browse the repository at this point in the history
…2161)

This pull request introduces the `isEmpty` utility function and
integrates it across various components to improve the handling of empty
values. The most important changes include the addition of the `isEmpty`
function, its use in form validation, and updates to the `ErrorSampler`
and `ProbabilisticSampler` components to handle empty values more
effectively.

### Introduction of `isEmpty` utility function:
*
[`frontend/webapp/utils/functions/resolvers/is-emtpy/index.ts`](diffhunk://#diff-134d27b73ff1fb66f7be69a1d2b2d0476adcc2ac12a120aaa2c92caa63402df1R1-R12):
Added a new `isEmpty` function to strictly check for empty values,
allowing values like `0` and `false`.
*
[`frontend/webapp/utils/functions/resolvers/index.ts`](diffhunk://#diff-24c64e1f6bad8c9ac4c2e338e9d6be1654e7da44da8447c1008d3aa080ef1f38R3):
Exported the new `isEmpty` function.

### Integration of `isEmpty` in form components:
*
[`frontend/webapp/containers/main/actions/action-form-body/custom-fields/error-sampler.tsx`](diffhunk://#diff-4b3cc5e7cbd14f55ad2bd0df1acb6014426f8fc8afb94e38d3e45f7ee51e5491L1-R3):
Updated to use `isEmpty` for checking empty values and added `useEffect`
to handle initial empty state.
[[1]](diffhunk://#diff-4b3cc5e7cbd14f55ad2bd0df1acb6014426f8fc8afb94e38d3e45f7ee51e5491L1-R3)
[[2]](diffhunk://#diff-4b3cc5e7cbd14f55ad2bd0df1acb6014426f8fc8afb94e38d3e45f7ee51e5491L27-R35)
*
[`frontend/webapp/containers/main/actions/action-form-body/custom-fields/probabilistic-sampler.tsx`](diffhunk://#diff-226efbc764ee3dc98d436cc3b76d524dc37a84cd0794bcd6c737178deb929d1fL1-R3):
Updated to use `isEmpty` for checking empty values and added `useEffect`
to handle initial empty state.
[[1]](diffhunk://#diff-226efbc764ee3dc98d436cc3b76d524dc37a84cd0794bcd6c737178deb929d1fL1-R3)
[[2]](diffhunk://#diff-226efbc764ee3dc98d436cc3b76d524dc37a84cd0794bcd6c737178deb929d1fL27-R35)

### Form validation improvements:
*
[`frontend/webapp/hooks/actions/useActionFormData.ts`](diffhunk://#diff-034891eac1659418ed1ceccc6d28858abafa1f6f5da688a2550123de5ee99841L2-R3):
Integrated `isEmpty` for form validation and added a console log for
debugging.
[[1]](diffhunk://#diff-034891eac1659418ed1ceccc6d28858abafa1f6f5da688a2550123de5ee99841L2-R3)
[[2]](diffhunk://#diff-034891eac1659418ed1ceccc6d28858abafa1f6f5da688a2550123de5ee99841R20-R21)
[[3]](diffhunk://#diff-034891eac1659418ed1ceccc6d28858abafa1f6f5da688a2550123de5ee99841L28-R34)

### Updates to reusable components:
*
[`frontend/webapp/reuseable-components/input-table/index.tsx`](diffhunk://#diff-511aed49818334957716043c1273ee4e2a4c6bdc789f95e3cc2958f4cf603a1eR5):
Used `isEmpty` to filter valid rows and handle empty values in the
`InputTable` component.
[[1]](diffhunk://#diff-511aed49818334957716043c1273ee4e2a4c6bdc789f95e3cc2958f4cf603a1eR5)
[[2]](diffhunk://#diff-511aed49818334957716043c1273ee4e2a4c6bdc789f95e3cc2958f4cf603a1eL73-R74)
[[3]](diffhunk://#diff-511aed49818334957716043c1273ee4e2a4c6bdc789f95e3cc2958f4cf603a1eL143-R146)
  • Loading branch information
BenElferink authored Jan 8, 2025
1 parent dd7b40b commit 26d1cbe
Show file tree
Hide file tree
Showing 6 changed files with 34 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
10 changes: 3 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 @@ -25,15 +25,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 26d1cbe

Please sign in to comment.