diff --git a/packages/components/src/components/organisms/CustomTable/CustomTableHeader/CustomTableHeader.tsx b/packages/components/src/components/organisms/CustomTable/CustomTableHeader/CustomTableHeader.tsx index b6186802..3cb3e792 100644 --- a/packages/components/src/components/organisms/CustomTable/CustomTableHeader/CustomTableHeader.tsx +++ b/packages/components/src/components/organisms/CustomTable/CustomTableHeader/CustomTableHeader.tsx @@ -13,6 +13,7 @@ import { useTranslation } from 'next-i18next' import { manageStickyHeaders, stickyBorderStyle } from '../../../../services' import { BaseTableCell, StickyTableCell } from '../CustomTable.styled' +import InfoTooltip from '../../../atoms/form/InfoTooltip' interface IProps { cssLeftValues: number[] @@ -116,6 +117,9 @@ function CustomTableHeader(props: IProps): JSX.Element { }} > {stickyHeader.label} + {stickyHeader.gridHeaderInfoTooltip.trim() && ( + + )} ))} @@ -135,7 +139,9 @@ function CustomTableHeader(props: IProps): JSX.Element { whiteSpace: 'nowrap', ...((header.type === DataContentType.SCORE || header.type === DataContentType.PRICE) && { width: '10%' }), - ...(header.type === DataContentType.STOCK && { width: '15%' }), + ...(header.type === DataContentType.STOCK && { + width: '15%', + }), ...(header.type === DataContentType.STRING && { maxWidth: 'fit-content', }), @@ -143,6 +149,9 @@ function CustomTableHeader(props: IProps): JSX.Element { }} > {t(header.label)} + {header.gridHeaderInfoTooltip.trim() && ( + + )} ))} diff --git a/packages/components/src/components/organisms/CustomTable/CustomTableRow/DraggableRow.tsx b/packages/components/src/components/organisms/CustomTable/CustomTableRow/DraggableRow.tsx index 80d1cbb2..1e71b91d 100644 --- a/packages/components/src/components/organisms/CustomTable/CustomTableRow/DraggableRow.tsx +++ b/packages/components/src/components/organisms/CustomTable/CustomTableRow/DraggableRow.tsx @@ -9,7 +9,6 @@ import { ITableHeader, ITableHeaderSticky, ITableRow, - getFieldState, getImageValue, } from '@elastic-suite/gally-admin-shared' @@ -150,11 +149,7 @@ function DraggableRow(props: IProps): JSX.Element { onChange={handleChange} row={tableRow} value={tableRow[stickyHeader.name]} - {...getFieldState( - tableRow, - stickyHeader.depends, - tableConfig[stickyHeader.name] - )} + data={tableRow} /> ))} @@ -180,11 +175,7 @@ function DraggableRow(props: IProps): JSX.Element { onChange={handleChange} row={tableRow} value={value} - {...getFieldState( - tableRow, - header.depends, - tableConfig[header.name] - )} + data={tableRow} /> ) diff --git a/packages/components/src/components/organisms/CustomTable/CustomTableRow/NonDraggableRow.tsx b/packages/components/src/components/organisms/CustomTable/CustomTableRow/NonDraggableRow.tsx index e2f6bd97..eb7140ad 100644 --- a/packages/components/src/components/organisms/CustomTable/CustomTableRow/NonDraggableRow.tsx +++ b/packages/components/src/components/organisms/CustomTable/CustomTableRow/NonDraggableRow.tsx @@ -9,7 +9,6 @@ import { ITableHeader, ITableHeaderSticky, ITableRow, - getFieldState, getImageValue, } from '@elastic-suite/gally-admin-shared' @@ -142,11 +141,7 @@ function NonDraggableRow(props: IProps): JSX.Element { onChange={handleChange} row={tableRow} value={tableRow[stickyHeader.name]} - {...getFieldState( - tableRow, - stickyHeader.depends, - tableConfig[stickyHeader.name] - )} + data={tableRow} /> ) @@ -172,11 +167,7 @@ function NonDraggableRow(props: IProps): JSX.Element { onChange={handleChange} row={tableRow} value={value} - {...getFieldState( - tableRow, - header.depends, - tableConfig[header.name] - )} + data={tableRow} /> ) diff --git a/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx b/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx index 57c9667d..1b6f018e 100644 --- a/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx +++ b/packages/components/src/components/stateful/FieldGuesser/EditableFieldGuesser.tsx @@ -2,7 +2,6 @@ import React, { SyntheticEvent } from 'react' import { useTranslation } from 'next-i18next' import { DataContentType, - IDependsForm, IExpansions, IFieldGuesserProps, IOption, @@ -23,7 +22,6 @@ import { IDoubleDatePickerValues } from '../../atoms/form/DoubleDatePickerWithou import DoubleDatePicker from '../../atoms/form/DoubleDatePicker' import { Box } from '@mui/material' import RequestTypeManager from '../../stateful/RequestTypeManager/RequestTypeManager' -import { isHiddenDepends } from '../../../services' import RulesManager from '../RulesManager/RulesManager' import Slider from '../../atoms/form/Slider' import Synonym from '../../atoms/form/Synonym' @@ -33,7 +31,6 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { const { diffValue, input, - disabled, label, multiple, name, @@ -46,7 +43,6 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { suffix, type, validation, - depends, requestTypeConfigurations, data, optionConfig, @@ -55,6 +51,7 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { error, helperText, replacementErrorsMessages, + disabled, } = props const { t } = useTranslation('common') @@ -85,17 +82,6 @@ function EditableFieldGuesser(props: IFieldGuesserProps): JSX.Element { } } - if (depends) { - const isHidden = isHiddenDepends( - depends instanceof Array ? (depends as IDependsForm[]) : [depends], - data - ) - - if (isHidden) { - return null - } - } - switch (input ?? type) { case DataContentType.NUMBER: case DataContentType.STRING: { diff --git a/packages/components/src/components/stateful/FieldGuesser/FieldGuesser.tsx b/packages/components/src/components/stateful/FieldGuesser/FieldGuesser.tsx index ca33a537..efbe17e0 100644 --- a/packages/components/src/components/stateful/FieldGuesser/FieldGuesser.tsx +++ b/packages/components/src/components/stateful/FieldGuesser/FieldGuesser.tsx @@ -1,15 +1,25 @@ import React from 'react' -import { IFieldGuesserProps } from '@elastic-suite/gally-admin-shared' +import { + IFieldGuesserProps, + getFieldState, +} from '@elastic-suite/gally-admin-shared' import EditableFieldGuesser from './EditableFieldGuesser' import ReadableFieldGuesser from './ReadableFieldGuesser' function FieldGuesser(props: IFieldGuesserProps): JSX.Element { const { editable, ...fieldProps } = props + const { visible, ...fieldStateProps } = getFieldState( + fieldProps.data, + fieldProps.depends + ) + + if (visible === false) return null + if (editable) { - return + return } - return + return } export default FieldGuesser diff --git a/packages/components/src/components/stateful/FieldGuesser/FormFieldGuesser.tsx b/packages/components/src/components/stateful/FieldGuesser/FormFieldGuesser.tsx index 560a554b..61d88be1 100644 --- a/packages/components/src/components/stateful/FieldGuesser/FormFieldGuesser.tsx +++ b/packages/components/src/components/stateful/FieldGuesser/FormFieldGuesser.tsx @@ -15,7 +15,11 @@ interface IFormFieldGuesserProps function FormFieldGuesser(props: IFormFieldGuesserProps): JSX.Element { const { data, field, ...fieldProps } = props const value = useValue(field, data) - return + + return ( + + // ) + ) } export default FormFieldGuesser diff --git a/packages/components/src/services/form.ts b/packages/components/src/services/form.ts index f1aaab9d..cfaf7ffa 100644 --- a/packages/components/src/services/form.ts +++ b/packages/components/src/services/form.ts @@ -1,5 +1,4 @@ import { - IDependsForm, IFetch, IFieldConfig, IHydraResponse, @@ -29,20 +28,6 @@ export function getDoubleDatePickerValue( return { fromDate: data?.fromDate, toDate: data?.toDate } } -export function isHiddenDepends( - dependsForm: IDependsForm[], - data: Record | undefined -): boolean { - return dependsForm.some((item) => { - const field = item?.field as string - const { value } = item - const fieldValue = data?.[field] - return ( - fieldValue === undefined || (value !== fieldValue && value !== undefined) - ) - }) -} - export function getRequestTypeData( data?: Record, limitationTypeOptionsApi?: IFetch> diff --git a/packages/shared/src/services/field.test.ts b/packages/shared/src/services/field.test.ts index 2360474a..b616225e 100644 --- a/packages/shared/src/services/field.test.ts +++ b/packages/shared/src/services/field.test.ts @@ -147,7 +147,7 @@ describe('Field service', () => { expect( getFieldState( { foo: 'bar', baz: true }, - { conditions: { baz: true }, disabled: true } + { conditions: { field: 'baz', value: false }, type: 'enabled' } ) ).toEqual({ disabled: true }) }) @@ -159,7 +159,7 @@ describe('Field service', () => { expect( getFieldState( { foo: 'bar', baz: true }, - { conditions: { baz: true }, disabled: true }, + { conditions: { field: 'baz', value: true }, type: 'enabled' }, { disabled: false } ) ).toEqual({ disabled: false }) diff --git a/packages/shared/src/services/field.ts b/packages/shared/src/services/field.ts index 2f6bbaea..36bd4a71 100644 --- a/packages/shared/src/services/field.ts +++ b/packages/shared/src/services/field.ts @@ -2,9 +2,9 @@ import { IDropdownApiOptions, IDropdownStaticOptions, IField, - IFieldCondition, IFieldConfig, IFieldConfigFormWithFieldset, + IFieldDepends, IFieldState, } from '../types' @@ -59,20 +59,54 @@ export function isDropdownStaticOptions( return 'values' in options } +/** + * Allows to return a state based on conditions dependent on another field. + * The field [field name] depends on the condition [condition] to be [type]. + */ export function getFieldState( - entity: Record, - depends?: IFieldCondition, + entity?: Record, + depends?: IFieldDepends, state: IFieldState = {} ): IFieldState { + if (!entity) return {} if (!depends?.conditions) { return state } - const { conditions, ...conditionalState } = depends - const conditionActive = Object.entries(conditions).every( - ([field, value]) => entity[field] === value - ) + const { conditions, type } = depends + + let conditionActive = false + + if (Array.isArray(conditions)) { + for (const item of conditions) { + if (!conditionActive) { + if (Array.isArray(item)) { + conditionActive = item.every( + ({ field, value }) => entity[field] === value + ) + } else { + const { field, value } = item + conditionActive = entity[field] === value + } + } else { + break + } + } + } else { + conditionActive = entity[conditions.field] === conditions.value + } + + const newState: IFieldState = {} + + switch (type) { + case 'visible': + newState.visible = conditionActive + break + case 'enabled': + newState.disabled = !conditionActive + } + return { - ...(conditionActive && conditionalState), + ...newState, ...state, } } diff --git a/packages/shared/src/services/form.ts b/packages/shared/src/services/form.ts index 4595be9e..a3a87fc9 100644 --- a/packages/shared/src/services/form.ts +++ b/packages/shared/src/services/form.ts @@ -1,7 +1,6 @@ import { TFunction } from 'next-i18next' import { IExpansions, - IField, IRequestType, IRequestTypesOptions, ISearchLimitations, @@ -138,14 +137,3 @@ export function getExpansionsErrorMessages(expansions: IExpansions): string[] { export function areExpansionsValid(expansions: IExpansions): boolean { return getExpansionsErrorMessages(expansions).length === 0 } - -export function isDependsField( - field: IField, - data: Record -): boolean { - return ( - !field?.gally?.depends || - (field.gally.depends?.field in data && - data[field.gally.depends.field] === field.gally.depends?.value) - ) -} diff --git a/packages/shared/src/services/table.ts b/packages/shared/src/services/table.ts index 9f4cfded..c079aa5d 100644 --- a/packages/shared/src/services/table.ts +++ b/packages/shared/src/services/table.ts @@ -120,6 +120,7 @@ export function getFieldHeader(field: IField, t: TFunction): IFieldConfig { ...fieldConfig, editable: field.gally?.editable && field.writeable, fieldset: field.gally?.fieldset, + gridHeaderInfoTooltip: field.gally?.gridHeaderInfoTooltip, id, input, infoTooltip: field.gally?.infoTooltip, diff --git a/packages/shared/src/types/field.ts b/packages/shared/src/types/field.ts index c66e0fb6..23e38702 100644 --- a/packages/shared/src/types/field.ts +++ b/packages/shared/src/types/field.ts @@ -5,17 +5,23 @@ import { DataContentType, ITableRow } from './customTables' import { IMultipleInputConfiguration, IMultipleValueFormat } from './hydra' import { IOption, IOptions } from './option' -export interface IFieldCondition { - conditions: Record +export interface IFieldState { disabled?: boolean + visible?: boolean } -export interface IFieldState { - disabled?: boolean +export interface IFieldCondition { + field: string + value: any +} + +export interface IFieldDepends { + type: 'enabled' | 'visible' + conditions: (IFieldCondition | IFieldCondition[])[] | IFieldCondition } export interface IFieldConfig extends IFieldState { - depends?: any + depends?: IFieldDepends editable?: boolean field?: IField fieldset?: string @@ -42,6 +48,7 @@ export interface IFieldConfig extends IFieldState { cellsStyle?: CSSProperties showError?: boolean replacementErrorsMessages?: Record + gridHeaderInfoTooltip?: string } export interface IFieldConfigFormWithFieldset { diff --git a/packages/shared/src/types/hydra.ts b/packages/shared/src/types/hydra.ts index 92b756e5..21120864 100644 --- a/packages/shared/src/types/hydra.ts +++ b/packages/shared/src/types/hydra.ts @@ -11,7 +11,7 @@ import { } from './jsonld' import { IOptions } from './option' import { IHydraSimpleCatalog } from './catalog' -// import { IFieldCondition } from './field' +import { IFieldDepends } from './field' export enum HydraType { ARRAY = 'array', @@ -111,7 +111,7 @@ export interface IMultipleValueFormat { export interface IGallyProperty { context?: Record - depends?: any + depends?: IFieldDepends editable?: boolean input?: string options?: IDropdownOptions & (IDropdownStaticOptions | IDropdownApiOptions) @@ -133,6 +133,7 @@ export interface IGallyProperty { placeholder?: string defaultValue?: unknown showError?: boolean + gridHeaderInfoTooltip?: string } export interface IDropdownOptions { objectKeyValue?: string