From 135f29d2a3d252314831767567a10c0e4c568237 Mon Sep 17 00:00:00 2001 From: rowheat02 Date: Mon, 27 Apr 2026 12:49:26 +0545 Subject: [PATCH 01/14] Slider Ui for Dynamic filter --- .../widgets/builder/wizard/FilterWizard.jsx | 8 +- .../components/AttributeSelector.jsx | 4 +- .../components/FilterAttributesSection.jsx | 5 +- .../FilterDataTab/hooks/useFilterData.js | 5 +- .../FilterDataTab/hooks/useLayerAttributes.js | 4 +- .../wizard/filter/FilterDataTab/index.jsx | 14 +- .../builder/wizard/filter/FilterLayoutTab.jsx | 170 +++++++++++++++--- .../builder/wizard/filter/FilterList.jsx | 4 +- .../builder/wizard/filter/FilterSlider.jsx | 152 ++++++++++++++++ .../filter/__tests__/FilterLayoutTab-test.jsx | 47 ++++- .../widgetbuilder/FilterBuilderContent.jsx | 16 +- .../plugins/widgetbuilder/FilterView.jsx | 23 ++- .../__tests__/FilterView-test.jsx | 68 ++++++- .../widgetbuilder/utils/filterBuilder.js | 7 +- web/client/themes/default/less/sliders.less | 14 ++ web/client/themes/default/less/wizard.less | 10 +- web/client/translations/data.de-DE.json | 13 ++ web/client/translations/data.en-US.json | 13 ++ web/client/translations/data.es-ES.json | 13 ++ web/client/translations/data.fr-FR.json | 13 ++ web/client/translations/data.it-IT.json | 13 ++ 21 files changed, 571 insertions(+), 45 deletions(-) create mode 100644 web/client/components/widgets/builder/wizard/filter/FilterSlider.jsx diff --git a/web/client/components/widgets/builder/wizard/FilterWizard.jsx b/web/client/components/widgets/builder/wizard/FilterWizard.jsx index 51459e41c0a..2a14013a0f9 100644 --- a/web/client/components/widgets/builder/wizard/FilterWizard.jsx +++ b/web/client/components/widgets/builder/wizard/FilterWizard.jsx @@ -57,6 +57,7 @@ const isFilterConfigValid = (editorData = {}) => { const FilterWizard = ({ filterData = {}, editorData = {}, + selectableItems = [], onChange = () => {}, onOpenLayerSelector = () => {}, openFilterEditor = () => {}, @@ -74,7 +75,8 @@ const FilterWizard = ({ onAddFilter = () => {}, onDeleteFilter = () => {}, onRenameFilter = () => {}, - onSelectionChange = () => {} + onSelectionChange = () => {}, + onSelectableItemsChange = () => {} }) => { const [activeTab, setActiveTab] = useState('data'); @@ -94,7 +96,7 @@ const FilterWizard = ({ const tabContents = { data: , - layout: , + layout: , actions: }; @@ -108,6 +110,7 @@ const FilterWizard = ({ selections={selections} getSelectionHandler={onSelectionChange} selectedFilterId={selectedFilterId} + onSelectableItemsChange={onSelectableItemsChange} /> { - onValueAttributeChange(option?.value); + onValueAttributeChange(option); }; const handleLabelAttributeChange = (option) => { - onLabelAttributeChange(option?.value); + onLabelAttributeChange(option); }; const handleSortByAttributeChange = (option) => { @@ -153,4 +153,3 @@ FilterAttributesSection.propTypes = { }; export default FilterAttributesSection; - diff --git a/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useFilterData.js b/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useFilterData.js index ecb41bce5ba..a1440a8a4e9 100644 --- a/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useFilterData.js +++ b/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useFilterData.js @@ -80,7 +80,9 @@ export const useFilterData = (data = {}) => { // Attributes const valueAttribute = filterData.valueAttribute ?? null; + const valueAttributeType = filterData.valueAttributeType ?? null; const labelAttribute = filterData.labelAttribute ?? null; + const labelAttributeType = filterData.labelAttributeType ?? null; const sortByAttribute = filterData.sortByAttribute ?? null; const sortOrder = filterData.sortOrder; @@ -111,7 +113,9 @@ export const useFilterData = (data = {}) => { // Attributes valueAttribute, + valueAttributeType, labelAttribute, + labelAttributeType, sortByAttribute, sortOrder, @@ -128,4 +132,3 @@ export const useFilterData = (data = {}) => { }; }, [data]); }; - diff --git a/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useLayerAttributes.js b/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useLayerAttributes.js index 7d7a8f7a266..3d7d998039f 100644 --- a/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useLayerAttributes.js +++ b/web/client/components/widgets/builder/wizard/filter/FilterDataTab/hooks/useLayerAttributes.js @@ -20,7 +20,8 @@ const getLayerKey = (layer, layerId = null) => { const mapAttributesToOptions = (attributes = []) => { return attributes.map(attribute => ({ value: attribute.value || attribute.attribute || attribute.name, - label: attribute.label || attribute.alias || attribute.value || attribute.attribute || attribute.name + label: attribute.label || attribute.alias || attribute.value || attribute.attribute || attribute.name, + type: attribute.type })); }; @@ -110,4 +111,3 @@ export const useLayerAttributes = (selectedLayer, hasLayerSelection = false) => error: attributesError }; }; - diff --git a/web/client/components/widgets/builder/wizard/filter/FilterDataTab/index.jsx b/web/client/components/widgets/builder/wizard/filter/FilterDataTab/index.jsx index d0be37fddc0..89f73158b35 100644 --- a/web/client/components/widgets/builder/wizard/filter/FilterDataTab/index.jsx +++ b/web/client/components/widgets/builder/wizard/filter/FilterDataTab/index.jsx @@ -85,8 +85,17 @@ const FilterDataTab = ({ }, [onEditorChange]); // Generic handlers using the factory function - const handleValueAttributeChange = createChangeHandler('data.valueAttribute'); - const handleLabelAttributeChange = createChangeHandler('data.labelAttribute'); + const handleValueAttributeChange = useCallback((option) => { + onChange('data.valueAttribute', option?.value); + onChange('data.valueAttributeType', option?.type); + if (!filterDataState.labelAttribute) { + onChange('data.labelAttributeType', option?.type); + } + }, [onChange, filterDataState.labelAttribute]); + const handleLabelAttributeChange = useCallback((option) => { + onChange('data.labelAttribute', option?.value); + onChange('data.labelAttributeType', option?.type); + }, [onChange]); const handleSortByAttributeChange = createChangeHandler('data.sortByAttribute'); const handleSortOrderChange = createChangeHandler('data.sortOrder'); const handleMaxFeaturesChange = createChangeHandler('data.maxFeatures'); @@ -207,4 +216,3 @@ FilterDataTab.propTypes = { }; export default FilterDataTab; - diff --git a/web/client/components/widgets/builder/wizard/filter/FilterLayoutTab.jsx b/web/client/components/widgets/builder/wizard/filter/FilterLayoutTab.jsx index cacac2aac69..60b6b9bd134 100644 --- a/web/client/components/widgets/builder/wizard/filter/FilterLayoutTab.jsx +++ b/web/client/components/widgets/builder/wizard/filter/FilterLayoutTab.jsx @@ -6,7 +6,7 @@ * LICENSE file in the root directory of this source tree. */ import React, { useState } from 'react'; -import { FormGroup, ControlLabel, InputGroup, FormControl, Panel, Glyphicon, Collapse, Checkbox } from 'react-bootstrap'; +import { FormGroup, ControlLabel, InputGroup, FormControl, Panel, Glyphicon, Collapse, Checkbox, Button, OverlayTrigger, Tooltip } from 'react-bootstrap'; import Select from 'react-select'; import ColorSelector from '../../../../style/ColorSelector'; import FontAwesomeIconSelector from './FontAwesomeIconSelector/FontAwesomeIconSelector'; @@ -34,11 +34,14 @@ const FilterLayoutTab = ({ data = {}, onChange = () => {}, onEditorChange = () => {}, - selections = {} + selections = {}, + selectableItems = [] }) => { const layout = data?.layout || {}; + const filterItems = Array.isArray(selectableItems) ? selectableItems : []; const [expandedPanel, setExpandedPanel] = useState("items"); const isStyleList = data?.data?.userDefinedType === USER_DEFINED_TYPES.STYLE_LIST; + const showTickAutofillButton = layout.variant === 'slider'; // Localized options for selection mode const selectedSelectionMode = SELECTION_MODE_OPTIONS.find(opt => opt.value === layout.selectionMode); @@ -53,11 +56,56 @@ const FilterLayoutTab = ({ DIRECTION_OPTIONS, selectedDirection ); + const isSliderVariant = layout.variant === 'slider'; + const variantOptions = [ + { value: 'checkbox', label: 'Checkbox' }, + { value: 'button', label: 'Button' }, + { value: 'dropdown', label: 'Dropdown' }, + { value: 'switch', label: 'Switch' }, + ...(layout.selectionMode === 'single' ? [{ value: 'slider', label: 'Slider' }] : []) + ]; + const localizedSelectionModeOptionsWithDisabledMultiple = localizedSelectionModeOptions.map(opt => ( + opt.value === 'multiple' && isSliderVariant + ? { ...opt, disabled: true } + : opt + )); const handlePanelToggle = (panelName) => { setExpandedPanel(expandedPanel === panelName ? null : panelName); }; + const handleVariantChange = (val) => { + onChange('layout.variant', val?.value); + if (val?.value === 'slider') { + onChange('layout.selectionMode', 'single'); + onEditorChange('selections', { + ...selections, + [data.id]: selections?.[data.id]?.length > 0 ? [selections[data.id][0]] : [] + }); + } + }; + + const handleSelectionModeChange = (val) => { + const nextSelectionMode = val?.value; + const currentSelections = selections?.[data.id] || []; + onChange('layout.selectionMode', nextSelectionMode); + onEditorChange('selections', { + ...selections, + [data.id]: nextSelectionMode === 'single' ? (currentSelections.length > 0 ? [currentSelections[0]] : []) : currentSelections + }); + if (nextSelectionMode !== 'single' && isSliderVariant) { + onChange('layout.variant', 'checkbox'); + } + }; + + const handleAutofillTickValues = () => { + const tickValues = filterItems + .map(item => item?.id) + .filter(item => item !== undefined && item !== null && item !== '') + .join(', '); + onChange('layout.tickValues', tickValues); + }; + return (
onChange('layout.variant', val?.value)} + onChange={handleVariantChange} /> @@ -205,18 +248,10 @@ const FilterLayoutTab = ({