Skip to content

Commit

Permalink
elyra-ai#510 'enum_filter' conditions for multiselect controls
Browse files Browse the repository at this point in the history
  • Loading branch information
caritaou committed Feb 25, 2021
1 parent 1b823ed commit add4919
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
@import "./checkbox/checkbox";
@import "./checkboxset/checkboxset";
@import "./dropdown/dropdown";
@import "./multiselect/multiselect";
@import "./expression/expression";
@import "./radioset/radioset";
@import "./textarea/textarea";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { MultiSelect } from "carbon-components-react";
import { isEqual, intersection } from "lodash";
import * as ControlUtils from "./../../util/control-utils";
import ValidationMessage from "./../../components/validation-message";
import classNames from "classnames";
Expand All @@ -28,18 +29,40 @@ import { formatMessage } from "./../../util/property-utils";
class MultiSelectControl extends React.Component {
constructor(props) {
super(props);
this.state = {
items: this.genSelectOptions(this.props.value),
selectedOptions: this.getSelectedOption(this.genSelectOptions(this.props.value), this.props.value)
};

this.getSelectedOption = this.getSelectedOption.bind(this);
this.genSelectOptions = this.genSelectOptions.bind(this);
this.handleOnChange = this.handleOnChange.bind(this);
this.updateValueFromFilterEnum = this.updateValueFromFilterEnum.bind(this);
}

componentDidMount() {
this.updateValueFromFilterEnum(true);
}

componentDidUpdate(prevProps) {
// only update if filter options have changed. Fixes issue where filter options are updated after value in setProperties
if (!isEqual(this.props.controlOpts, prevProps.controlOpts)) {
this.updateValueFromFilterEnum();
}
}

getSelectedOption(options, selectedValues) {
const values = PropertyUtils.stringifyFieldValue(selectedValues, this.props.control);
const selectedOptions = [];
if (values) {
values.forEach((value) => selectedOptions.push(options.find(function(option) {
return option.value === value;
})));
values.forEach((value) => {
const selected = options.find(function(option) {
return option.value === value;
});
if (typeof selected !== "undefined") {
selectedOptions.push(selected);
}
});
}
return selectedOptions;
}
Expand All @@ -52,11 +75,24 @@ class MultiSelectControl extends React.Component {
label: this.props.controlOpts.valueLabels[j]
});
}
const selectedOptions = this.getSelectedOption(options, selectedValues);
return {
options: options,
selectedOptions: selectedOptions
};
return options;
}

// this is needed in order to reset the property value when a value is filtered out.
updateValueFromFilterEnum(skipValidateInput) {
// update property value if value isn't in current enum value
if (this.props.value !== null &&
typeof this.props.value !== "undefined" && this.props.value.length > 0 && intersection(this.props.controlOpts.values, this.props.value).length === 0) {
let defaultValue = [];
// set to default value if default value is in filtered enum list
if (this.props.control.valueDef && this.props.control.valueDef.defaultValue &&
intersection(this.props.controlOpts.values, this.props.control.valueDef.defaultValue).length === this.props.control.valueDef.defaultValue.length) {
defaultValue = this.props.control.valueDef.defaultValue;
}

this.props.controller.updatePropertyValue(this.props.propertyId, defaultValue, skipValidateInput);
}
this.setState({ items: this.genSelectOptions(this.props.value) });
}

handleOnChange(evt) {
Expand All @@ -68,7 +104,14 @@ class MultiSelectControl extends React.Component {
}

render() {
const multiSelectDropdown = this.genSelectOptions(this.props.value);
// This workaround is required for modifying the list of initial selected items
if (this.state && this.state.selectedOptions) {
this.state.selectedOptions.splice(0);
}
const selectedOptions = this.getSelectedOption(this.genSelectOptions(this.props.value), this.props.value);
selectedOptions.forEach((option) => {
this.state.selectedOptions.push(option);
});

const listBoxMenuIconTranslationIds = {
"close.menu": formatMessage(this.reactIntl, MESSAGE_KEYS.DROPDOWN_TOOLTIP_CLOSEMENU),
Expand All @@ -83,7 +126,7 @@ class MultiSelectControl extends React.Component {
const defaultOptionsSelectedLabel = formatMessage(this.reactIntl, MESSAGE_KEYS.MULTISELECT_DROPDOWN_OPTIONS_SELECTED_LABEL);

let label = "";
if (multiSelectDropdown.selectedOptions.length === 0) { // Display message for no options selected
if (this.state.selectedOptions.length === 0) { // Display message for no options selected
label = this.props.controller.getResource(overrideEmptyLabelKey, defaultEmptyLabel);
} else { // Display message for multiple options selected
label = this.props.controller.getResource(overrideOptionsSelectedLabelKey, defaultOptionsSelectedLabel);
Expand All @@ -93,21 +136,23 @@ class MultiSelectControl extends React.Component {
if (this.props.control.filterable) {
dropdownComponent = (<MultiSelect.Filterable
id={`${ControlUtils.getDataId(this.props.propertyId)}-multiselect-filterable`}
className={classNames({ "properties-multiselect-none-selected": this.state.selectedOptions.length === 0 })}
disabled={this.props.state === STATES.DISABLED}
translateWithId={(id) => listBoxMenuIconTranslationIds[id]}
items={multiSelectDropdown.options}
initialSelectedItems={multiSelectDropdown.selectedOptions}
items={this.state.items}
initialSelectedItems={this.state.selectedOptions}
onChange={this.handleOnChange}
placeholder={label}
light
/>);
} else {
dropdownComponent = (<MultiSelect
id={`${ControlUtils.getDataId(this.props.propertyId)}-multiselect`}
className={classNames({ "properties-multiselect-none-selected": this.state.selectedOptions.length === 0 })}
disabled={this.props.state === STATES.DISABLED}
translateWithId={(id) => listBoxMenuIconTranslationIds[id]}
items={multiSelectDropdown.options}
initialSelectedItems={multiSelectDropdown.selectedOptions}
items={this.state.items}
initialSelectedItems={this.state.selectedOptions}
onChange={this.handleOnChange}
label={label}
light
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Copyright 2021 Elyra Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

.properties-multiselect-none-selected {

// This is required to override the multiselect 'clear all' option
.bx--list-box__selection--multi {
display: none;
}
// Remove padding left from 'clear all' option
input.bx--text-input--empty {
padding-left: $spacing-05;
}

// Remove the checkmark from the checkbox if nothing is selected
.bx--checkbox:checked + .bx--checkbox-label::before, // filterable multiselect
.bx--checkbox-label[data-contained-checkbox-state="true"]::before { // regular multiselect
background-color: transparent;
}
.bx--checkbox:checked + .bx--checkbox-label::after, // filterable multiselect
.bx--checkbox-label[data-contained-checkbox-state="true"]::after { // regular multiselect
transform: scale(0) rotate(-45deg);
}

// Remove the rows highlighted if nothing is selected
div.bx--list-box__menu-item--active {
background-color: transparent;
}
.bx--list-box__menu-item--highlighted .bx--list-box__menu-item__option, // filterable multiselect
.bx--list-box__menu-item--active + .bx--list-box__menu-item > .bx--list-box__menu-item__option {
border-top-color: $button-separator;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
"multiselect_hidden": [],
"disabled": true,
"multiselect_disabled": [],
"filter": false,
"multiselect_filtered": ["orange"],
"filter_default": false,
"multiselect_filtered_default": ["purple"],
"multiselect_table": [
[
["cat"],
Expand Down Expand Up @@ -168,6 +172,39 @@
],
"required": true
},
{
"id": "filter",
"type": "boolean"
},
{
"id": "multiselect_filtered",
"enum": [
"red",
"orange",
"yellow",
"green",
"blue",
"purple"
],
"required": true
},
{
"id": "filter_default",
"type": "boolean"
},
{
"id": "multiselect_filtered_default",
"enum": [
"red",
"orange",
"yellow",
"green",
"blue",
"purple"
],
"default": ["blue"],
"required": true
},
{
"id": "multiselect_table",
"type": "array[multiselect_table_struct]",
Expand Down Expand Up @@ -349,6 +386,38 @@
},
"control": "multiselect"
},
{
"parameter_ref": "filter",
"label": {
"default": "Filter 'multiselect filtered'"
}
},
{
"parameter_ref": "multiselect_filtered",
"label": {
"default": "multiselect filtered"
},
"description": {
"default": "multiselect dropdown to have values 'red', 'blue', and 'green'"
},
"control": "multiselect"
},
{
"parameter_ref": "filter_default",
"label": {
"default": "Filter 'multiselect filtered default'"
}
},
{
"parameter_ref": "multiselect_filtered_default",
"label": {
"default": "multiselect filtered with default value"
},
"description": {
"default": "multiselect dropdown to have values 'red', 'blue', and 'green'"
},
"control": "multiselect"
},
{
"parameter_ref": "multiselect_table",
"label": {
Expand Down Expand Up @@ -439,6 +508,19 @@
"multiselect_disabled"
]
},
{
"id": "multiselect-filters",
"label": {
"default": "Filters"
},
"type": "controls",
"parameter_refs": [
"filter",
"multiselect_filtered",
"filter_default",
"multiselect_filtered_default"
]
},
{
"id": "multiselect-tables",
"label": {
Expand Down Expand Up @@ -529,6 +611,44 @@
}
}
}
},
{
"enum_filter": {
"target": {
"parameter_ref": "multiselect_filtered",
"values": [
"red",
"blue",
"green"
]
},
"evaluate": {
"condition": {
"parameter_ref": "filter",
"op": "equals",
"value": true
}
}
}
},
{
"enum_filter": {
"target": {
"parameter_ref": "multiselect_filtered_default",
"values": [
"red",
"blue",
"green"
]
},
"evaluate": {
"condition": {
"parameter_ref": "filter_default",
"op": "equals",
"value": true
}
}
}
}
],
"resources": {
Expand Down

0 comments on commit add4919

Please sign in to comment.