Skip to content

Commit

Permalink
#1354 Support empty list placeholder in selectcolumn and selechschema (
Browse files Browse the repository at this point in the history
  • Loading branch information
nmgokhale authored Feb 7, 2023
1 parent 63034ac commit 000e441
Show file tree
Hide file tree
Showing 11 changed files with 369 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Controller from "../../../src/common-properties/properties-controller";

import propertyUtils from "../../_utils_/property-utils";
import selectcolumnParamDef from "../../test_resources/paramDefs/selectcolumn_paramDef.json";
import selectcolumnEmptyListParamDef from "../../test_resources/paramDefs/selectcolumn_emptylist_paramDef.json";
import selectcolumnMultiInputParamDef from "../../test_resources/paramDefs/selectcolumn_multiInput_paramDef.json";

const emptyValueIndicator = "...";
Expand Down Expand Up @@ -148,7 +149,8 @@ describe("selectcolumn control renders correctly", () => {
expect(dropdownList).to.be.length(4);
expect(dropdownList.at(0).text()).to.equal(emptyValueIndicator);
});
it("should have '...' as first selected option when fields is empty", () => {
it("should have 'No options available' as first selected option when fields is empty", () => {
const defaultEmptyListPlaceholder = "No options available";
controller.setDatasetMetadata([]);
controller.setPropertyValues(
{ "targetField": null }
Expand All @@ -162,15 +164,15 @@ describe("selectcolumn control renders correctly", () => {
/>
);
let dropdownWrapper = wrapper.find("div[data-id='properties-targetField']");
expect(dropdownWrapper.find("button > span").text()).to.equal(emptyValueIndicator);
expect(dropdownWrapper.find("button > span").text()).to.equal(defaultEmptyListPlaceholder);
// open the dropdown
const dropdownButton = dropdownWrapper.find("button");
dropdownButton.simulate("click");
// select the first item
dropdownWrapper = wrapper.find("div[data-id='properties-targetField']");
const dropdownList = dropdownWrapper.find("div.bx--list-box__menu-item");
expect(dropdownList).to.be.length(1);
expect(dropdownList.at(0).text()).to.equal(emptyValueIndicator);
expect(dropdownList.at(0).text()).to.equal(defaultEmptyListPlaceholder);
});

it("should allow empty string to be set as valid field in selectcolumn control", () => {
Expand Down Expand Up @@ -602,3 +604,29 @@ describe("selectcolumn classnames appear correctly", () => {
expect(wrapper.find(".table-subpanel-selectcolumn-control-class")).to.have.length(1);
});
});

describe("Empty list selectcolumn control with default and custom placeholder text", () => {
let wrapper;
beforeEach(() => {
const renderedObject = propertyUtils.flyoutEditorForm(selectcolumnEmptyListParamDef);
wrapper = renderedObject.wrapper;
});
afterEach(() => {
wrapper.unmount();
});
it("should have default placeholder text when fields is empty", () => {
// No resource_key added for field2_panel property
const dropdownWrapper = wrapper.find("div[data-id='properties-field2_panel']");
expect(dropdownWrapper.find("button > span").text()).to.equal("No options available");
// Verify dropdown is enabled
expect(dropdownWrapper.find("Dropdown").props()).to.have.property("disabled", false);
});

it("should have custom placeholder text when fields is empty and selectcolumn control should be disabled", () => {
// "field1_panel.emptyList.placeholder" resource key is added in paramDef
const dropdownWrapper = wrapper.find("div[data-id='properties-field1_panel']");
expect(dropdownWrapper.find("button > span").text()).to.equal("Empty list placeholder text");
// Verify dropdown is disabled
expect(dropdownWrapper.find("Dropdown").props()).to.have.property("disabled", true);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import selectschemaParamDef from "../../test_resources/paramDefs/selectschema_pa

const controller = new Controller();

const emptyValueIndicator = "...";
const emptyValueIndicator = "No options available";

const control = {
"name": "selectschema",
Expand Down Expand Up @@ -64,7 +64,7 @@ describe("selectschema renders correctly", () => {
expect(wrapper.prop("controller")).to.equal(controller);
expect(wrapper.prop("propertyId")).to.equal(propertyId);
});
it("should have '...' as first selected option", () => {
it("should have 'No options available' as first selected option for empty list", () => {
controller.setPropertyValues(
{ "test-selectschema": null }
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,8 @@ describe("structureeditor control renders correctly", () => {
expect(dropdownList.at(0).text()).to.equal(emptyValueIndicator);
});

it("should have '...' as first selected option when fields is empty", () => {
it("should have 'No options available' as first selected option when fields is empty", () => {
const defaultEmptyListPlaceholder = "No options available";
controller.setDatasetMetadata([]);
controller.setPropertyValues(
{ "group-o-fields": null }
Expand All @@ -191,15 +192,15 @@ describe("structureeditor control renders correctly", () => {
</Provider>
);
let dropdownWrapper = wrapper.find("div[data-id='properties-group-o-fields_0']");
expect(dropdownWrapper.find("button > span").text()).to.equal(emptyValueIndicator);
expect(dropdownWrapper.find("button > span").text()).to.equal(defaultEmptyListPlaceholder);
// open the dropdown
const dropdownButton = dropdownWrapper.find("button");
dropdownButton.simulate("click");
// select the first item
dropdownWrapper = wrapper.find("div[data-id='properties-group-o-fields_0']");
const dropdownList = dropdownWrapper.find("div.bx--list-box__menu-item");
expect(dropdownList).to.be.length(1);
expect(dropdownList.at(0).text()).to.equal(emptyValueIndicator);
expect(dropdownList.at(0).text()).to.equal(defaultEmptyListPlaceholder);
});

it("should allow empty string to be set as valid field in structureeditor control", () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"titleDefinition": {
"title": "Select Column Empty list"
},
"current_parameters": {},
"parameters": [
{
"id": "field1_panel",
"type": "string",
"role": "column",
"required": true
},
{
"id": "field2_panel",
"type": "string",
"role": "column",
"required": true
}
],
"complex_types": [],
"uihints": {
"id": "selectcolumn",
"icon": "images/default.svg",
"label": {
"default": "Select Column"
},
"parameter_info": [
{
"parameter_ref": "field1_panel",
"label": {
"default": "Field1 Panel"
},
"description": {
"default": "Disabled selectcolumn with empty list and custom placeholder text."
}
},
{
"parameter_ref": "field2_panel",
"label": {
"default": "Field2 Panel"
},
"description": {
"default": "selectcolumn with empty list and default placeholder text."
}
}
],
"complex_type_info": [],
"group_info": [
{
"id": "selectcolumn-values",
"label": {
"default": "Values"
},
"type": "panels",
"group_info": [
{
"id": "selectcolumn-values1",
"label": {
"default": "Values"
},
"type": "columnSelection",
"parameter_refs": [
"field1_panel",
"field2_panel"
]
}
]
}
]
},
"conditions": [],
"resources": {
"field1_panel.emptyList.placeholder": "Empty list placeholder text"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,6 @@
"virtualizedTable.row.checkbox.label": "Select row {row_index} from {table_label}",
"properties.empty.table.text": "To begin, click \"{button_label}\"",
"label.indicator.required": "(required)",
"label.indicator.optional": "(optional)"
"label.indicator.optional": "(optional)",
"emptyList.placeholder": "No options available"
}
Original file line number Diff line number Diff line change
Expand Up @@ -102,5 +102,6 @@
"virtualizedTable.row.checkbox.label": "[Esperanto~Select row {row_index} from {table_label}~~~~~~~~~~eo]",
"properties.empty.table.text": "[Esperanto~To begin, click \"{button_label}\"~~~~~eo]",
"label.indicator.required": "[Esperanto~(required)~~~~~~eo]",
"label.indicator.optional": "[Esperanto~(optional)~~~~~~eo]"
"label.indicator.optional": "[Esperanto~(optional)~~~~~~eo]",
"emptyList.placeholder": "[Esperanto~No options available~~~~~~eo]"
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@ export const MESSAGE_KEYS = {
SHOW_PASSWORD_TOOLTIP: "passwordShow.tooltip",
HIDE_PASSWORD_TOOLTIP: "passwordHide.tooltip",
LABEL_INDICATOR_REQUIRED: "label.indicator.required",
LABEL_INDICATOR_OPTIONAL: "label.indicator.optional"
LABEL_INDICATOR_OPTIONAL: "label.indicator.optional",
EMPTY_LIST_PLACEHOLDER: "emptyList.placeholder"
};

export const TRUNCATE_LIMIT = 10000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import React from "react";
import PropTypes from "prop-types";
import { connect } from "react-redux";
import { SelectItem, Select, Dropdown, ComboBox } from "carbon-components-react";
import { isEqual } from "lodash";
import { isEqual, isEmpty } from "lodash";
import * as ControlUtils from "./../../util/control-utils";
import ValidationMessage from "./../../components/validation-message";
import classNames from "classnames";
Expand All @@ -30,11 +30,22 @@ import { formatMessage } from "./../../util/property-utils";
class DropDown extends React.Component {
constructor(props) {
super(props);
this.reactIntl = props.controller.getReactIntl();
this.emptyLabel = "...";
if (props.control.additionalText) {
this.disableEmptyListDropdown = false;
if (isEmpty(props.controlOpts)) {
// For empty dropdown, get placeholder text from resources
const overrideEmptyListPlaceholder = `${this.props.control.name}.emptyList.placeholder`;
const defaultEmptyListPlaceholder = formatMessage(this.reactIntl, MESSAGE_KEYS.EMPTY_LIST_PLACEHOLDER);
this.emptyLabel = props.controller.getResource(overrideEmptyListPlaceholder, defaultEmptyListPlaceholder);
// Disable empty dropdown when [property_id].emptyList.placeholder is set in resources
if (this.emptyLabel !== defaultEmptyListPlaceholder) {
this.disableEmptyListDropdown = true;
}
} else if (props.control.additionalText) {
// For non-empty dropdown, get placeholder text from place_holder_text in parameter_info
this.emptyLabel = props.control.additionalText;
}
this.reactIntl = props.controller.getReactIntl();
this.id = ControlUtils.getControlId(this.props.propertyId);
this.handleChange = this.handleChange.bind(this);
this.handleComboOnChange = this.handleComboOnChange.bind(this);
Expand Down Expand Up @@ -205,7 +216,7 @@ class DropDown extends React.Component {
hideLabel
inline
labelText={this.props.control.label ? this.props.control.label.text : ""}
disabled={this.props.state === STATES.DISABLED}
disabled={this.props.state === STATES.DISABLED || this.disableEmptyListDropdown}
onChange={this.handleChange}
value={selection}
light={this.props.controller.getLight() && this.props.control.light}
Expand All @@ -217,7 +228,7 @@ class DropDown extends React.Component {
{...validationProps}
ariaLabel={this.props.control.label ? this.props.control.label.text : ""}
id={`${ControlUtils.getDataId(this.props.propertyId)}-dropdown`}
disabled={this.props.state === STATES.DISABLED}
disabled={this.props.state === STATES.DISABLED || this.disableEmptyListDropdown}
placeholder={dropDown.selectedOption.label}
selectedItem={dropDown.selectedOption.label}
items={dropDown.options}
Expand All @@ -231,7 +242,7 @@ class DropDown extends React.Component {
dropdownComponent = (<Dropdown
{...validationProps}
id={`${ControlUtils.getDataId(this.props.propertyId)}-dropdown`}
disabled={this.props.state === STATES.DISABLED}
disabled={this.props.state === STATES.DISABLED || this.disableEmptyListDropdown}
type="default"
items={dropDown.options}
onChange={this.handleChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ import {
SOMEOFSELECT_PROPS_INFO,
FORCED_CHECKBOX_SET_PROPS_INFO,
SELECTSCHEMA_PROPS_INFO,
SELECTSCHEMA_EMPTY_PROPS_INFO,
SELECTCOLUMN_PROPS_INFO,
SELECTCOLUMN_EMPTY_PROPS_INFO,
SELECTCOLUMN_MULTI_INPUT_PROPS_INFO,
SELECTCOLUMNS_PROPS_INFO,
SELECTCOLUMNS_MULTI_INPUT_PROPS_INFO,
Expand Down Expand Up @@ -1419,6 +1421,25 @@ class CommonPropertiesComponents extends React.Component {
</pre>
</div>
</div>
<p>When <span className="harness-highlight">dataset_metadata</span> is not provided,
selectschema control will display default placeholder text <span className="harness-highlight"> "No options available"</span>.
This placeholder text can be customized by setting <span className="harness-highlight">[parameter_id].emptyList.placeholder</span> in resources section.
When custom empty list placeholder text is provided, common-properties will disable the empty list control.</p>
<div className="harness-section-row">
<div className="harness-section-column">
<CommonProperties
propertiesInfo={SELECTSCHEMA_EMPTY_PROPS_INFO}
propertiesConfig={this.propertiesConfig}
light={this.state.light}
/>
{this.renderRightFlyoutButton(SELECTSCHEMA_EMPTY_PROPS_INFO)}
</div>
<div className="harness-section-column harness-section-column-code">
<pre className="harness-json-block">
{this.jsonReplacer(SELECTSCHEMA_EMPTY_PROPS_INFO.parameterDef, "all")}
</pre>
</div>
</div>
</div>
<div className="harness-properties-documentation-panels-controls-component">
<h3 id="--selectcolumn" className="harness-section-subtitle">selectcolumn</h3>
Expand All @@ -1441,6 +1462,25 @@ class CommonPropertiesComponents extends React.Component {
</pre>
</div>
</div>
<p>When <span className="harness-highlight">dataset_metadata</span> is not provided,
selectcolumn control will display default placeholder text <span className="harness-highlight"> "No options available"</span>.
This placeholder text can be customized by setting <span className="harness-highlight">[parameter_id].emptyList.placeholder</span> in resources section.
When custom empty list placeholder text is provided, common-properties will disable the empty list control.</p>
<div className="harness-section-row">
<div className="harness-section-column">
<CommonProperties
propertiesInfo={SELECTCOLUMN_EMPTY_PROPS_INFO}
propertiesConfig={this.propertiesConfig}
light={this.state.light}
/>
{this.renderRightFlyoutButton(SELECTCOLUMN_EMPTY_PROPS_INFO)}
</div>
<div className="harness-section-column harness-section-column-code">
<pre className="harness-json-block">
{this.jsonReplacer(SELECTCOLUMN_EMPTY_PROPS_INFO.parameterDef, "all")}
</pre>
</div>
</div>
<p>If multiple input schemas are supported by a given node type, then the type of the parameter for the selectColumn control must be
of <span className="harness-highlight">type object</span>, and the role must be set to <span className="harness-highlight">column</span>.
The <span className="harness-highlight">selectcolumn</span> control will display all the fields from both schemas,
Expand Down
Loading

0 comments on commit 000e441

Please sign in to comment.