From d382513bbf37eeabd5efffba1be57b024342156c Mon Sep 17 00:00:00 2001 From: Norbert Csaba Herczeg Date: Fri, 23 Aug 2024 19:01:14 +0200 Subject: [PATCH] JNG-5888 filter context --- .../components/table/EagerTable.tsx.snapshot | 6 -- .../components/table/LazyTable.tsx.snapshot | 6 -- .../actor/public/i18n/system_default.json.hbs | 26 +++---- .../actor/public/i18n/system_en-US.json.hbs | 26 +++---- .../actor/public/i18n/system_hu-HU.json.hbs | 6 +- .../src/components/table/ContextMenu.tsx.hbs | 72 ++++++++++++++++++- .../src/components/table/EagerTable.tsx.hbs | 10 --- .../src/components/table/LazyTable.tsx.hbs | 10 --- .../actor/src/utilities/filter-helper.ts.hbs | 59 ++++++++------- pom.xml | 2 +- 10 files changed, 135 insertions(+), 88 deletions(-) diff --git a/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/EagerTable.tsx.snapshot b/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/EagerTable.tsx.snapshot index b5c6ebc3..bfde96e2 100644 --- a/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/EagerTable.tsx.snapshot +++ b/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/EagerTable.tsx.snapshot @@ -536,12 +536,6 @@ export function EagerTable { - handleFilterModelChange({ - ...filterModel, - items: [...filterModel.items, mapFilterToFilterModel(filter)], - }); - }} /> ); diff --git a/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/LazyTable.tsx.snapshot b/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/LazyTable.tsx.snapshot index 93cc098b..12456ae6 100644 --- a/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/LazyTable.tsx.snapshot +++ b/judo-ui-react-itest/ActionGroupTestPro/action_group_test_pro__god/src/test/resources/snapshots/frontend-react/src/components/table/LazyTable.tsx.snapshot @@ -731,12 +731,6 @@ export function LazyTable { - handleFilterModelChange({ - ...filterModel, - items: [...filterModel.items, mapFilterToFilterModel(filter)], - }); - }} /> ); diff --git a/judo-ui-react/src/main/resources/actor/public/i18n/system_default.json.hbs b/judo-ui-react/src/main/resources/actor/public/i18n/system_default.json.hbs index d801e6df..8d89783e 100644 --- a/judo-ui-react/src/main/resources/actor/public/i18n/system_default.json.hbs +++ b/judo-ui-react/src/main/resources/actor/public/i18n/system_default.json.hbs @@ -74,6 +74,18 @@ "judo.modal.filter.apply": "Apply", "judo.modal.filter.clear-all": "Clear all", "judo.modal.filter.operation": "Operation", + "judo.modal.filter.lessThan": "Less than", + "judo.modal.filter.greaterThan": "Greater than", + "judo.modal.filter.lessOrEqual": "Less or equal", + "judo.modal.filter.greaterOrEqual": "Greater or equal", + "judo.modal.filter.equal": "Equal", + "judo.modal.filter.notEqual": "Not equal", + "judo.modal.filter.matches": "Matches", + "judo.modal.filter.like": "Like", + "judo.modal.filter.equals": "Equals", + "judo.modal.filter.notEquals": "Not equals", + "judo.modal.filter.isNotEmpty": "Is not empty", + "judo.modal.filter.isEmpty": "Is empty", "judo.modal.confirm.confirm": "Yes", "judo.modal.confirm.cancel": "No", "judo.modal.confirm.confirm-title": "Confirm action", @@ -111,20 +123,10 @@ "judo.component.Table.ContextMenu.copyText": "Copy text", "judo.component.Table.ContextMenu.filterBy": "Filter based on the selected value", "judo.component.Table.ContextMenu.excludeBy": "Exclude based on the selected value", + "judo.component.Table.ContextMenu.filterByEmpty": "Filter by empty values", + "judo.component.Table.ContextMenu.filterByNonEmpty": "Filter by non-empty values", "judo.applications.available_applications": "Available applications", "judo.applications.change": "Switch Application", - "judo.modal.filter.lessThan": "Less than", - "judo.modal.filter.greaterThan": "Greater than", - "judo.modal.filter.lessOrEqual": "Less or equal", - "judo.modal.filter.greaterOrEqual": "Greater or equal", - "judo.modal.filter.equal": "Equal", - "judo.modal.filter.notEqual": "Not equal", - "judo.modal.filter.matches": "Matches", - "judo.modal.filter.like": "Like", - "judo.modal.filter.equals": "Equals", - "judo.modal.filter.notEquals": "Not equals", - "judo.modal.filter.isDefined": "Is defined", - "judo.modal.filter.isUndefined": "Is undefined", "judo.error.error": "Error", "judo.error.unhandled": "An unhandled error occurred.", "judo.error.unmappable": "An error occurred, but we could not display the error info.", diff --git a/judo-ui-react/src/main/resources/actor/public/i18n/system_en-US.json.hbs b/judo-ui-react/src/main/resources/actor/public/i18n/system_en-US.json.hbs index d801e6df..8d89783e 100644 --- a/judo-ui-react/src/main/resources/actor/public/i18n/system_en-US.json.hbs +++ b/judo-ui-react/src/main/resources/actor/public/i18n/system_en-US.json.hbs @@ -74,6 +74,18 @@ "judo.modal.filter.apply": "Apply", "judo.modal.filter.clear-all": "Clear all", "judo.modal.filter.operation": "Operation", + "judo.modal.filter.lessThan": "Less than", + "judo.modal.filter.greaterThan": "Greater than", + "judo.modal.filter.lessOrEqual": "Less or equal", + "judo.modal.filter.greaterOrEqual": "Greater or equal", + "judo.modal.filter.equal": "Equal", + "judo.modal.filter.notEqual": "Not equal", + "judo.modal.filter.matches": "Matches", + "judo.modal.filter.like": "Like", + "judo.modal.filter.equals": "Equals", + "judo.modal.filter.notEquals": "Not equals", + "judo.modal.filter.isNotEmpty": "Is not empty", + "judo.modal.filter.isEmpty": "Is empty", "judo.modal.confirm.confirm": "Yes", "judo.modal.confirm.cancel": "No", "judo.modal.confirm.confirm-title": "Confirm action", @@ -111,20 +123,10 @@ "judo.component.Table.ContextMenu.copyText": "Copy text", "judo.component.Table.ContextMenu.filterBy": "Filter based on the selected value", "judo.component.Table.ContextMenu.excludeBy": "Exclude based on the selected value", + "judo.component.Table.ContextMenu.filterByEmpty": "Filter by empty values", + "judo.component.Table.ContextMenu.filterByNonEmpty": "Filter by non-empty values", "judo.applications.available_applications": "Available applications", "judo.applications.change": "Switch Application", - "judo.modal.filter.lessThan": "Less than", - "judo.modal.filter.greaterThan": "Greater than", - "judo.modal.filter.lessOrEqual": "Less or equal", - "judo.modal.filter.greaterOrEqual": "Greater or equal", - "judo.modal.filter.equal": "Equal", - "judo.modal.filter.notEqual": "Not equal", - "judo.modal.filter.matches": "Matches", - "judo.modal.filter.like": "Like", - "judo.modal.filter.equals": "Equals", - "judo.modal.filter.notEquals": "Not equals", - "judo.modal.filter.isDefined": "Is defined", - "judo.modal.filter.isUndefined": "Is undefined", "judo.error.error": "Error", "judo.error.unhandled": "An unhandled error occurred.", "judo.error.unmappable": "An error occurred, but we could not display the error info.", diff --git a/judo-ui-react/src/main/resources/actor/public/i18n/system_hu-HU.json.hbs b/judo-ui-react/src/main/resources/actor/public/i18n/system_hu-HU.json.hbs index d5e0debd..3eea3d69 100644 --- a/judo-ui-react/src/main/resources/actor/public/i18n/system_hu-HU.json.hbs +++ b/judo-ui-react/src/main/resources/actor/public/i18n/system_hu-HU.json.hbs @@ -84,8 +84,8 @@ "judo.modal.filter.like": "Tartalmazza", "judo.modal.filter.equals": "Egyenlő", "judo.modal.filter.notEquals": "Nem egyenlő", - "judo.modal.filter.isDefined": "Létezik", - "judo.modal.filter.isUndefined": "Nem létezik", + "judo.modal.filter.isNotEmpty": "Létezik", + "judo.modal.filter.isEmpty": "Nem létezik", "judo.modal.confirm.confirm": "Igen", "judo.modal.confirm.cancel": "Nem", "judo.modal.confirm.confirm-title": "Megerősítés szükséges", @@ -123,6 +123,8 @@ "judo.component.Table.ContextMenu.copyText": "Szöveg másolása", "judo.component.Table.ContextMenu.filterBy": "Szűrés a kiválasztott érték alapján", "judo.component.Table.ContextMenu.excludeBy": "Kizárás a kiválasztott érték alapján", + "judo.component.Table.ContextMenu.filterByEmpty": "Szűrés üres mezőre", + "judo.component.Table.ContextMenu.filterByNonEmpty": "Szűrés nem üres mezőre", "judo.applications.available_applications": "Választható alkalmazások", "judo.applications.change": "Alkalmazás váltás", "judo.error.error": "Hiba", diff --git a/judo-ui-react/src/main/resources/actor/src/components/table/ContextMenu.tsx.hbs b/judo-ui-react/src/main/resources/actor/src/components/table/ContextMenu.tsx.hbs index cf4d5dc1..c4297d21 100644 --- a/judo-ui-react/src/main/resources/actor/src/components/table/ContextMenu.tsx.hbs +++ b/judo-ui-react/src/main/resources/actor/src/components/table/ContextMenu.tsx.hbs @@ -16,7 +16,6 @@ export interface ContextMenuProps> { filterOptions: FilterOption[]; data: P[]; onFilterByCell: (filter: Filter) => void; - onExcludeByCell: (filter: Filter) => void; } export interface ContextMenuApi { @@ -25,7 +24,7 @@ export interface ContextMenuApi { export const ContextMenu = forwardRef>(>(props: ContextMenuProps, ref: ForwardedRef) => { const { t } = useTranslation(); - const { filters, data, onFilterByCell, onExcludeByCell, filterOptions, columns } = props; + const { filters, data, onFilterByCell, filterOptions, columns } = props; const [selectedColumn, setSelectedColumn] = useState | undefined>(); const [selectedRow, setSelectedRow] = useState(); const [selectedRowData, setSelectedRowData] = useState

(); @@ -114,7 +113,7 @@ export const ContextMenu = forwardRef const filterOption = filterOptions.find((f) => f.attributeName === field)!; const filterType: FilterType = filterOption.filterType; - onExcludeByCell({ + onFilterByCell({ valueId: `${field as string}-value-${new Date().toISOString()}`, operationId: `${field as string}-operation-${new Date().toISOString()}`, id: field as string, @@ -141,6 +140,61 @@ export const ContextMenu = forwardRef closeContextMenu(); }; + const filterByEmpty = () => { + if (field) { + const filterOption = filterOptions.find((f) => f.attributeName === field)!; + const filterType: FilterType = filterOption.filterType; + onFilterByCell({ + valueId: `${field as string}-value-${new Date().toISOString()}`, + operationId: `${field as string}-operation-${new Date().toISOString()}`, + id: field as string, + filterOption: { + id: `${field as string}-option-${new Date().toISOString()}`, + attributeName: field as string, + filterType: filterType, + ...(filterType === FilterType.enumeration + ? { + enumValues: filterOption.enumValues, + } + : {}), + }, + filterBy: { + value: null, + operator: 'isEmpty' as Operation, + }, + }); + } + closeContextMenu(); + }; + + const filterByNonEmpty = () => { + if (field) { + const filterOption = filterOptions.find((f) => f.attributeName === field)!; + const filterType: FilterType = filterOption.filterType; + + onFilterByCell({ + valueId: `${field as string}-value-${new Date().toISOString()}`, + operationId: `${field as string}-operation-${new Date().toISOString()}`, + id: field as string, + filterOption: { + id: `${field as string}-option-${new Date().toISOString()}`, + attributeName: field as string, + filterType: filterType, + ...(filterType === FilterType.enumeration + ? { + enumValues: filterOption.enumValues, + } + : {}), + }, + filterBy: { + value: null, + operator: 'isNotEmpty' as Operation, + }, + }); + } + closeContextMenu(); + }; + return (

{t('judo.component.Table.ContextMenu.excludeBy', { defaultValue: 'Exclude based on the selected value', columnName: selectedColumn?.headerName, field: field, value: selectedValue }) as string} )} + + + + {t('judo.component.Table.ContextMenu.filterByEmpty', { defaultValue: 'Filter by empty values', columnName: selectedColumn?.headerName, field: field, value: selectedValue }) as string} + + + + + + {t('judo.component.Table.ContextMenu.filterByNonEmpty', { defaultValue: 'Filter by non-empty values', columnName: selectedColumn?.headerName, field: field, value: selectedValue }) as string} + + ); }, diff --git a/judo-ui-react/src/main/resources/actor/src/components/table/EagerTable.tsx.hbs b/judo-ui-react/src/main/resources/actor/src/components/table/EagerTable.tsx.hbs index 9fe65337..bb54f8fa 100644 --- a/judo-ui-react/src/main/resources/actor/src/components/table/EagerTable.tsx.hbs +++ b/judo-ui-react/src/main/resources/actor/src/components/table/EagerTable.tsx.hbs @@ -565,16 +565,6 @@ export function EagerTable { - {{# if isUseInlineColumnFilters }} - handleFilterModelChange({ - ...filterModel, - items: [...filterModel.items, mapFilterToFilterModel(filter)], - }); - {{ else }} - handleFiltersChange([...filters, filter]); - {{/ if }} - } } /> {{/ if }} diff --git a/judo-ui-react/src/main/resources/actor/src/components/table/LazyTable.tsx.hbs b/judo-ui-react/src/main/resources/actor/src/components/table/LazyTable.tsx.hbs index 88216d70..94ab4ca5 100644 --- a/judo-ui-react/src/main/resources/actor/src/components/table/LazyTable.tsx.hbs +++ b/judo-ui-react/src/main/resources/actor/src/components/table/LazyTable.tsx.hbs @@ -739,16 +739,6 @@ export function LazyTable { - {{# if isUseInlineColumnFilters }} - handleFilterModelChange({ - ...filterModel, - items: [...filterModel.items, mapFilterToFilterModel(filter)], - }); - {{ else }} - handleFiltersChange([...filters, filter]); - {{/ if }} - } } /> {{/ if }} diff --git a/judo-ui-react/src/main/resources/actor/src/utilities/filter-helper.ts.hbs b/judo-ui-react/src/main/resources/actor/src/utilities/filter-helper.ts.hbs index a70b9af5..edf58eb1 100644 --- a/judo-ui-react/src/main/resources/actor/src/utilities/filter-helper.ts.hbs +++ b/judo-ui-react/src/main/resources/actor/src/utilities/filter-helper.ts.hbs @@ -98,7 +98,7 @@ export const getOperatorsByFilter = (filter: Filter): string[] => { }; export const isFilterWithoutValue = (filter: Filter) => { - return ['isDefined', 'isUndefined'].includes(getOperationEnumValue(filter, filter.filterBy.operator)) + return ['isNotEmpty', 'isEmpty'].includes(getOperationEnumValue(filter, filter.filterBy.operator)); }; export const ucFirst = (str: string): string => { @@ -117,7 +117,7 @@ export const mapFiltersToQueryCustomizerProperty = (filters: Filter[], property: const notEquals = 'not' + ucFirst(equals); return { value: null, - operator: (filter.filterBy.operator === 'isDefined' ? notEquals : equals) as Operation, + operator: (filter.filterBy.operator === 'isNotEmpty' ? notEquals : equals) as Operation, }; } return { @@ -192,9 +192,9 @@ export function filterByStringOperation(filter: Filter, data: T[]): T[] { return data.filter((d) => (d[attributeName] as string).localeCompare(filter.filterBy.value) <= 0); case _StringOperation.lessThan: return data.filter((d) => (d[attributeName] as string).localeCompare(filter.filterBy.value) < 0); - case _StringOperation.isDefined: + case _StringOperation.isNotEmpty: return data.filter((d) => d[attributeName] !== null && d[attributeName] !== undefined); - case _StringOperation.isUndefined: + case _StringOperation.isEmpty: return data.filter((d) => d[attributeName] === null || d[attributeName] === undefined); default: return [...data]; @@ -216,9 +216,9 @@ export function filterByNumericOperation(filter: Filter, data: T[]): T[] { return data.filter((d) => (d[attributeName] as number) > filter.filterBy.value); case _NumericOperation.greaterOrEqual: return data.filter((d) => (d[attributeName] as number) >= filter.filterBy.value); - case _NumericOperation.isDefined: + case _NumericOperation.isNotEmpty: return data.filter((d) => d[attributeName] !== null && d[attributeName] !== undefined); - case _NumericOperation.isUndefined: + case _NumericOperation.isEmpty: return data.filter((d) => d[attributeName] === null || d[attributeName] === undefined); default: return [...data]; @@ -240,9 +240,9 @@ export function filterByDateOperation(filter: Filter, data: T[]): T[] { return data.filter((d) => compareAsc(d[attributeName] as Date, filter.filterBy.value) > 0); case _NumericOperation.greaterOrEqual: return data.filter((d) => compareAsc(d[attributeName] as Date, filter.filterBy.value) >= 0); - case _NumericOperation.isDefined: + case _NumericOperation.isNotEmpty: return data.filter((d) => d[attributeName] !== null && d[attributeName] !== undefined); - case _NumericOperation.isUndefined: + case _NumericOperation.isEmpty: return data.filter((d) => d[attributeName] === null || d[attributeName] === undefined); default: return [...data]; @@ -257,11 +257,11 @@ export function filterByBooleanOperation(filter: Filter, data: T[]): T[] { if (d[attributeName] === undefined || d[attributeName] === null) { return filter.filterBy.value === undefined || filter.filterBy.value === null; } - return (d[attributeName] as boolean) === filter.filterBy.value + return (d[attributeName] as boolean) === filter.filterBy.value; }); - case _BooleanOperation.isDefined: + case _BooleanOperation.isNotEmpty: return data.filter((d) => d[attributeName] !== null && d[attributeName] !== undefined); - case _BooleanOperation.isUndefined: + case _BooleanOperation.isEmpty: return data.filter((d) => d[attributeName] === null || d[attributeName] === undefined); default: return [...data]; @@ -275,9 +275,9 @@ export function filterByEnumerationOperation(filter: Filter, data: T[]): T[] return data.filter((d) => d[attributeName] === filter.filterBy.value); case _EnumerationOperation.notEquals: return data.filter((d) => d[attributeName] !== filter.filterBy.value); - case _EnumerationOperation.isDefined: + case _EnumerationOperation.isNotEmpty: return data.filter((d) => d[attributeName] !== null && d[attributeName] !== undefined); - case _EnumerationOperation.isUndefined: + case _EnumerationOperation.isEmpty: return data.filter((d) => d[attributeName] === null || d[attributeName] === undefined); default: return [...data]; @@ -294,10 +294,10 @@ function mapStringOperator(operator: string): _StringOperation { return _StringOperation.notEqual; } if (operator === 'isEmpty') { - return _StringOperation.isUndefined; + return _StringOperation.isEmpty; } if (operator === 'isNotEmpty') { - return _StringOperation.isDefined; + return _StringOperation.isNotEmpty; } // contains @@ -321,10 +321,10 @@ function mapNumericOperator(operator: string): _NumericOperation { return _NumericOperation.lessOrEqual; } if (operator === 'isEmpty') { - return _NumericOperation.isUndefined; + return _NumericOperation.isEmpty; } if (operator === 'isNotEmpty') { - return _NumericOperation.isDefined; + return _NumericOperation.isNotEmpty; } // = @@ -351,10 +351,10 @@ function mapDateOperator(operator: string): _NumericOperation { return _NumericOperation.lessOrEqual; } if (operator === 'isEmpty') { - return _NumericOperation.isUndefined; + return _NumericOperation.isEmpty; } if (operator === 'isNotEmpty') { - return _NumericOperation.isDefined; + return _NumericOperation.isNotEmpty; } // is @@ -371,10 +371,10 @@ function mapSingleSelectOperator(operator: string): _EnumerationOperation { return _EnumerationOperation.notEquals; } if (operator === 'isEmpty') { - return _EnumerationOperation.isUndefined; + return _EnumerationOperation.isEmpty; } if (operator === 'isNotEmpty') { - return _EnumerationOperation.isDefined; + return _EnumerationOperation.isNotEmpty; } // is @@ -464,6 +464,13 @@ export function mapFilterModelToFilters(filterModel: GridFilterModel, filterOpti return filters; } +export function operatorToMUIOperator(operator: string, equals: string, notEquals: string): string { + if (operator === 'isEmpty' || operator === 'isNotEmpty') { + return operator; + } + return (operator === 'equal' || operator === 'equals') ? equals : notEquals; +} + // Used by cell context menus export function mapFilterToFilterModel(filter: Filter): GridFilterItem { const filterOption = filter.filterOption; @@ -477,33 +484,33 @@ export function mapFilterToFilterModel(filter: Filter): GridFilterItem { return { ...res, value: filterBy.value, - operator: filterBy.operator === _StringOperation.equal ? 'equals' : 'not', + operator: operatorToMUIOperator(filterBy.operator, 'equals', 'not'), }; case FilterType.numeric: return { ...res, value: filterBy.value, - operator: filterBy.operator === _NumericOperation.equal ? '=' : '!=', + operator: operatorToMUIOperator(filterBy.operator, '=', '!='), }; case FilterType.date: case FilterType.dateTime: return { ...res, value: filterBy.value, - operator: filterBy.operator === _NumericOperation.equal ? 'is' : 'not', + operator: operatorToMUIOperator(filterBy.operator, 'is', 'not'), }; case FilterType.boolean: case FilterType.trinaryLogic: return { ...res, value: String(filterBy.value), - operator: (filterBy.operator === 'equal' || filterBy.operator === 'equals') ? 'is' : 'not', + operator: operatorToMUIOperator(filterBy.operator, 'is', 'not'), }; case FilterType.enumeration: return { ...res, value: filterBy.value, - operator: filterBy.operator === _EnumerationOperation.equals ? 'is' : 'not', + operator: operatorToMUIOperator(filterBy.operator , 'is', 'not'), }; default: return { diff --git a/pom.xml b/pom.xml index 3062e543..ad814f23 100644 --- a/pom.xml +++ b/pom.xml @@ -57,7 +57,7 @@ 1.1.0.20240725_123755_3c5f2837_develop 1.0.0.20240712_085217_8319ce27_develop - 1.0.0.20240815_130502_30c0059e_feature_JNG_3980_filter_empty_values + 1.0.0.20240823_165725_58575058_feature_JNG_5888_filter_context 3.0.0-M7