feat: Tree Select widget (#6271)
* feat: Tree Select * feat: styling multiselect * fix: selected values * fix: remove console statement * fix: popup position * fix: selection types * fix: Form validation using TreeSelect * feat: Add Label to TreeSelect * fix: styling * fix: Dropdown search * fix: Add Entity Definitions * fix: Entity Definition * Feat: Add clear icon * fix: validation * fix: options validation * fix: Styling issues * fix: build error * Fix: Separate Tree Select widget * fix: issues and add validation * fix: Options Validation * fix: issues with build * fix: yarn * fix: changes * fix * Fix: select component * fix: PR issues * fix: merge conflicts * fix: issues * fix: all issues * test: added test * fix: failing test
This commit is contained in:
parent
146f536190
commit
15b26f823e
128
app/client/cypress/fixtures/TreeSelectDsl.json
Normal file
128
app/client/cypress/fixtures/TreeSelectDsl.json
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
{
|
||||||
|
"dsl":{
|
||||||
|
"widgetName":"MainContainer",
|
||||||
|
"backgroundColor":"none",
|
||||||
|
"rightColumn":1034.3999999999999,
|
||||||
|
"snapColumns":64,
|
||||||
|
"detachFromLayout":true,
|
||||||
|
"widgetId":"0",
|
||||||
|
"topRow":0,
|
||||||
|
"bottomRow":1990,
|
||||||
|
"containerStyle":"none",
|
||||||
|
"snapRows":125,
|
||||||
|
"parentRowSpace":1,
|
||||||
|
"type":"CANVAS_WIDGET",
|
||||||
|
"canExtend":true,
|
||||||
|
"version":38,
|
||||||
|
"minHeight":2000,
|
||||||
|
"parentColumnSpace":1,
|
||||||
|
"dynamicTriggerPathList":[],
|
||||||
|
"dynamicBindingPathList":[],
|
||||||
|
"leftColumn":0,
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"widgetName":"MultiSelectTree1",
|
||||||
|
"displayName":"Multi Select Tree",
|
||||||
|
"iconSVG":"/static/media/icon.f264210c.svg",
|
||||||
|
"labelText":"Label",
|
||||||
|
"topRow":38,
|
||||||
|
"bottomRow":44.88,
|
||||||
|
"parentRowSpace":10,
|
||||||
|
"type":"MULTI_SELECT_TREE_WIDGET",
|
||||||
|
"hideCard":false,
|
||||||
|
"mode":"SHOW_ALL",
|
||||||
|
"defaultOptionValue":[],
|
||||||
|
"parentColumnSpace":15.974999999999998,
|
||||||
|
"leftColumn":18,
|
||||||
|
"options":[
|
||||||
|
{
|
||||||
|
"label":"Blue",
|
||||||
|
"value":"BLUE",
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"label":"Dark Blue",
|
||||||
|
"value":"DARK BLUE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"Light Blue",
|
||||||
|
"value":"LIGHT BLUE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"Green",
|
||||||
|
"value":"GREEN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"Red",
|
||||||
|
"value":"RED"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placeholderText":"select option(s)",
|
||||||
|
"isDisabled":false,
|
||||||
|
"key":"1zu067mn51",
|
||||||
|
"isRequired":false,
|
||||||
|
"rightColumn":34,
|
||||||
|
"widgetId":"zvm3vcs5gp",
|
||||||
|
"isVisible":true,
|
||||||
|
"version":1,
|
||||||
|
"expandAll":false,
|
||||||
|
"parentId":"0",
|
||||||
|
"renderMode":"CANVAS",
|
||||||
|
"isLoading":false,
|
||||||
|
"allowClear":false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"widgetName":"SingleSelectTree1",
|
||||||
|
"displayName":"Single Select Tree",
|
||||||
|
"iconSVG":"/static/media/icon.f815ebe3.svg",
|
||||||
|
"labelText":"Label",
|
||||||
|
"topRow":58,
|
||||||
|
"bottomRow":64.8,
|
||||||
|
"parentRowSpace":10,
|
||||||
|
"type":"SINGLE_SELECT_TREE_WIDGET",
|
||||||
|
"hideCard":false,
|
||||||
|
"defaultOptionValue":"BLUE",
|
||||||
|
"parentColumnSpace":15.974999999999998,
|
||||||
|
"leftColumn":17,
|
||||||
|
"options":[
|
||||||
|
{
|
||||||
|
"label":"Blue",
|
||||||
|
"value":"BLUE",
|
||||||
|
"children":[
|
||||||
|
{
|
||||||
|
"label":"Dark Blue",
|
||||||
|
"value":"DARK BLUE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"Light Blue",
|
||||||
|
"value":"LIGHT BLUE"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"Green",
|
||||||
|
"value":"GREEN"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label":"Red",
|
||||||
|
"value":"RED"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"placeholderText":"select option",
|
||||||
|
"isDisabled":false,
|
||||||
|
"key":"cul8w70bzs",
|
||||||
|
"isRequired":false,
|
||||||
|
"rightColumn":33,
|
||||||
|
"widgetId":"0zloh94nd4",
|
||||||
|
"isVisible":true,
|
||||||
|
"version":1,
|
||||||
|
"expandAll":false,
|
||||||
|
"parentId":"0",
|
||||||
|
"renderMode":"CANVAS",
|
||||||
|
"isLoading":false,
|
||||||
|
"allowClear":false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
const dsl = require("../../../../fixtures/TreeSelectDsl.json");
|
||||||
|
|
||||||
|
describe("Tree Select Widget", function() {
|
||||||
|
beforeEach(() => {
|
||||||
|
cy.addDsl(dsl);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Open Existing MultiSelectTree from created Widgets list", () => {
|
||||||
|
cy.get(".bp3-icon-caret-right ~ .t--entity-name:contains(Widgets)").click({
|
||||||
|
multiple: true,
|
||||||
|
});
|
||||||
|
cy.get(
|
||||||
|
".bp3-icon-caret-right ~ .t--entity-name:contains(MultiSelectTree1)",
|
||||||
|
).click({
|
||||||
|
multiple: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Open Existing SingleSelectTree from created Widgets list", () => {
|
||||||
|
cy.get(".bp3-icon-caret-right ~ .t--entity-name:contains(Widgets)").click({
|
||||||
|
multiple: true,
|
||||||
|
});
|
||||||
|
cy.get(
|
||||||
|
".bp3-icon-caret-right ~ .t--entity-name:contains(SingleSelectTree1)",
|
||||||
|
).click({
|
||||||
|
multiple: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
const dsl = require("../../../../fixtures/TreeSelectDsl.json");
|
||||||
|
const formWidgetsPage = require("../../../../locators/FormWidgets.json");
|
||||||
|
const publish = require("../../../../locators/publishWidgetspage.json");
|
||||||
|
const commonlocators = require("../../../../locators/commonlocators.json");
|
||||||
|
|
||||||
|
describe("MultiSelectTree Widget Functionality", function() {
|
||||||
|
before(() => {
|
||||||
|
cy.addDsl(dsl);
|
||||||
|
});
|
||||||
|
it("Selects value with enter in default value", () => {
|
||||||
|
cy.openPropertyPane("multiselecttreewidget");
|
||||||
|
cy.testJsontext("defaultvalue", "RED\n");
|
||||||
|
cy.get(formWidgetsPage.multiselecttreeWidget)
|
||||||
|
.find(".rc-tree-select-selection-item-content")
|
||||||
|
.first()
|
||||||
|
.should("have.text", "Red");
|
||||||
|
});
|
||||||
|
it(" To Validate Options", function() {
|
||||||
|
cy.get(formWidgetsPage.treeSelectInput)
|
||||||
|
.first()
|
||||||
|
.click({ force: true });
|
||||||
|
cy.get(formWidgetsPage.treeSelectInput)
|
||||||
|
.first()
|
||||||
|
.type("light");
|
||||||
|
cy.treeSelectDropdown("Light Blue");
|
||||||
|
});
|
||||||
|
it("To Unchecked Visible Widget", function() {
|
||||||
|
cy.togglebarDisable(commonlocators.visibleCheckbox);
|
||||||
|
cy.PublishtheApp();
|
||||||
|
cy.get(
|
||||||
|
publish.multiselecttreewidget + " " + ".rc-tree-select-multiple",
|
||||||
|
).should("not.exist");
|
||||||
|
cy.get(publish.backToEditor).click();
|
||||||
|
});
|
||||||
|
it(" To Check Visible Widget", function() {
|
||||||
|
cy.openPropertyPane("multiselecttreewidget");
|
||||||
|
cy.togglebar(commonlocators.visibleCheckbox);
|
||||||
|
cy.PublishtheApp();
|
||||||
|
cy.get(
|
||||||
|
publish.multiselecttreewidget + " " + ".rc-tree-select-multiple",
|
||||||
|
).should("be.visible");
|
||||||
|
cy.get(publish.backToEditor).click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
// put your clean up code if any
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
const dsl = require("../../../../fixtures/TreeSelectDsl.json");
|
||||||
|
const formWidgetsPage = require("../../../../locators/FormWidgets.json");
|
||||||
|
const publish = require("../../../../locators/publishWidgetspage.json");
|
||||||
|
const commonlocators = require("../../../../locators/commonlocators.json");
|
||||||
|
|
||||||
|
describe("MultiSelectTree Widget Functionality", function() {
|
||||||
|
before(() => {
|
||||||
|
cy.addDsl(dsl);
|
||||||
|
});
|
||||||
|
it("Selects value with enter in default value", () => {
|
||||||
|
cy.openPropertyPane("singleselecttreewidget");
|
||||||
|
cy.testJsontext("defaultvalue", "RED\n");
|
||||||
|
cy.get(formWidgetsPage.singleselecttreeWidget)
|
||||||
|
.find(".rc-tree-select-selection-item")
|
||||||
|
.first()
|
||||||
|
.should("have.text", "Red");
|
||||||
|
});
|
||||||
|
it(" To Validate Options", function() {
|
||||||
|
cy.get(formWidgetsPage.treeSelectInput)
|
||||||
|
.last()
|
||||||
|
.click({ force: true });
|
||||||
|
cy.get(formWidgetsPage.treeSelectInput)
|
||||||
|
.last()
|
||||||
|
.type("light");
|
||||||
|
cy.treeSelectDropdown("Light Blue");
|
||||||
|
});
|
||||||
|
it("To Unchecked Visible Widget", function() {
|
||||||
|
cy.togglebarDisable(commonlocators.visibleCheckbox);
|
||||||
|
cy.PublishtheApp();
|
||||||
|
cy.get(
|
||||||
|
publish.singleselecttreewidget + " " + ".rc-tree-select-single",
|
||||||
|
).should("not.exist");
|
||||||
|
cy.get(publish.backToEditor).click();
|
||||||
|
});
|
||||||
|
it(" To Check Visible Widget", function() {
|
||||||
|
cy.openPropertyPane("singleselecttreewidget");
|
||||||
|
cy.togglebar(commonlocators.visibleCheckbox);
|
||||||
|
cy.PublishtheApp();
|
||||||
|
cy.get(
|
||||||
|
publish.singleselecttreewidget + " " + ".rc-tree-select-single",
|
||||||
|
).should("be.visible");
|
||||||
|
cy.get(publish.backToEditor).click();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
afterEach(() => {
|
||||||
|
// put your clean up code if any
|
||||||
|
});
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
"checkboxWidget": ".t--draggable-checkboxwidget",
|
"checkboxWidget": ".t--draggable-checkboxwidget",
|
||||||
"dropdownWidget": ".t--draggable-dropdownwidget",
|
"dropdownWidget": ".t--draggable-dropdownwidget",
|
||||||
"multiselectWidget": ".t--draggable-multiselectwidget",
|
"multiselectWidget": ".t--draggable-multiselectwidget",
|
||||||
|
"multiselecttreeWidget": ".t--draggable-multiselecttreewidget",
|
||||||
|
"singleselecttreeWidget": ".t--draggable-singleselecttreewidget",
|
||||||
"dropdownSelectionType": ".t--property-control-selectiontype .bp3-popover-target",
|
"dropdownSelectionType": ".t--property-control-selectiontype .bp3-popover-target",
|
||||||
"radioWidget": ".t--draggable-radiogroupwidget",
|
"radioWidget": ".t--draggable-radiogroupwidget",
|
||||||
"checkboxGroupWidget": ".t--draggable-checkboxgroupwidget",
|
"checkboxGroupWidget": ".t--draggable-checkboxgroupwidget",
|
||||||
|
|
@ -22,6 +24,7 @@
|
||||||
"labelvalue": ".t--draggable-dropdownwidget label",
|
"labelvalue": ".t--draggable-dropdownwidget label",
|
||||||
"dropdownInput": ".bp3-tag-input-values",
|
"dropdownInput": ".bp3-tag-input-values",
|
||||||
"mulitiselectInput": ".rc-select-selection-search-input",
|
"mulitiselectInput": ".rc-select-selection-search-input",
|
||||||
|
"treeSelectInput": ".rc-tree-select-selection-search-input",
|
||||||
"labelradio": ".t--draggable-radiogroupwidget label",
|
"labelradio": ".t--draggable-radiogroupwidget label",
|
||||||
"labelCheckboxGroup": ".t--draggable-checkboxgroupwidget label",
|
"labelCheckboxGroup": ".t--draggable-checkboxgroupwidget label",
|
||||||
"deleteradiovalue": ".t--property-control-options mask",
|
"deleteradiovalue": ".t--property-control-options mask",
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@
|
||||||
"imageWidget": ".t--widget-imagewidget",
|
"imageWidget": ".t--widget-imagewidget",
|
||||||
"dropdownWidget": ".t--widget-dropdownwidget",
|
"dropdownWidget": ".t--widget-dropdownwidget",
|
||||||
"multiselectwidget": ".t--widget-multiselectwidget",
|
"multiselectwidget": ".t--widget-multiselectwidget",
|
||||||
|
"multiselecttreewidget": ".t--widget-multiselecttreewidget",
|
||||||
|
"singleselecttreewidget": ".t--widget-singleselecttreewidget",
|
||||||
"tabWidget": ".t--widget-tabswidget",
|
"tabWidget": ".t--widget-tabswidget",
|
||||||
"chartWidget": ".t--widget-chartwidget",
|
"chartWidget": ".t--widget-chartwidget",
|
||||||
"horizontalTab": ".t--widget-chartwidget g[class*='-scrollContainer'] rect",
|
"horizontalTab": ".t--widget-chartwidget g[class*='-scrollContainer'] rect",
|
||||||
|
|
|
||||||
|
|
@ -1805,6 +1805,14 @@ Cypress.Commands.add("dropdownMultiSelectDynamic", (text) => {
|
||||||
.click({ force: true })
|
.click({ force: true })
|
||||||
.should("have.text", text);
|
.should("have.text", text);
|
||||||
});
|
});
|
||||||
|
Cypress.Commands.add("treeSelectDropdown", (text) => {
|
||||||
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||||
|
cy.wait(2000);
|
||||||
|
cy.get(".tree-select-dropdown")
|
||||||
|
.contains(text)
|
||||||
|
.click({ force: true })
|
||||||
|
.should("have.text", text);
|
||||||
|
});
|
||||||
|
|
||||||
Cypress.Commands.add("dropdownDynamicUpdated", (text) => {
|
Cypress.Commands.add("dropdownDynamicUpdated", (text) => {
|
||||||
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
// eslint-disable-next-line cypress/no-unnecessary-waiting
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@
|
||||||
"prismjs": "^1.24.0",
|
"prismjs": "^1.24.0",
|
||||||
"rc-pagination": "^3.1.3",
|
"rc-pagination": "^3.1.3",
|
||||||
"rc-select": "^12.1.10",
|
"rc-select": "^12.1.10",
|
||||||
|
"rc-tree-select": "^4.4.0-alpha.2",
|
||||||
"re-reselect": "^3.4.0",
|
"re-reselect": "^3.4.0",
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-base-table": "^1.9.1",
|
"react-base-table": "^1.9.1",
|
||||||
|
|
|
||||||
1
app/client/src/assets/icons/widget/multi-tree-select.svg
Normal file
1
app/client/src/assets/icons/widget/multi-tree-select.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.75" y="0.75" width="18.5" height="6.5" stroke="#EAEAEA" stroke-width="1.5"/><path d="M7.99985 10.05L14.9998 10.05V11.55L7.99985 11.55L7.99985 10.05Z" fill="#EAEAEA"/><path d="M7.99985 14.75H13.9998V16.25L7.99985 16.25L7.99985 14.75Z" fill="#EAEAEA"/><path d="M5.99985 10.5L2.99985 10.5L4.49985 12L5.99985 10.5Z" fill="#EAEAEA"/><path d="M6 15L3 15L4.5 16.5L6 15Z" fill="#EAEAEA"/><path fill-rule="evenodd" clip-rule="evenodd" d="M0 6.5V20H18V6.5H0ZM1.5 18.5V8H16.5V18.5H1.5Z" fill="#EAEAEA"/><path d="M3 3.25H11V4.75H3V3.25Z" fill="#EAEAEA"/><path d="M12 3.25H17V4.75H12V3.25Z" fill="#EAEAEA"/></svg>
|
||||||
|
After Width: | Height: | Size: 707 B |
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.75" y="0.75" width="18.5" height="6.5" stroke="#EAEAEA" stroke-width="1.5"/><path d="M7.99985 10.05L14.9998 10.05V11.55L7.99985 11.55L7.99985 10.05Z" fill="#EAEAEA"/><path d="M7.99985 14.75H13.9998V16.25L7.99985 16.25L7.99985 14.75Z" fill="#EAEAEA"/><path d="M5.99985 10.5L2.99985 10.5L4.49985 12L5.99985 10.5Z" fill="#EAEAEA"/><path d="M6 15L3 15L4.5 16.5L6 15Z" fill="#EAEAEA"/><path fill-rule="evenodd" clip-rule="evenodd" d="M0 6.5V20H18V6.5H0ZM1.5 18.5V8H16.5V18.5H1.5Z" fill="#EAEAEA"/><path d="M3 3.19995H17V4.69995H3V3.19995Z" fill="#EAEAEA"/></svg>
|
||||||
|
After Width: | Height: | Size: 664 B |
|
|
@ -139,6 +139,14 @@ export const HelpMap: Record<string, { path: string; searchKey: string }> = {
|
||||||
path: "/widget-reference/menu-button",
|
path: "/widget-reference/menu-button",
|
||||||
searchKey: "Menu Button",
|
searchKey: "Menu Button",
|
||||||
},
|
},
|
||||||
|
TREE_MULTI_SELECT_WIDGET: {
|
||||||
|
path: "/widget-reference/tree-multi-select",
|
||||||
|
searchKey: "Tree Multi Select",
|
||||||
|
},
|
||||||
|
TREE_SINGLE_SELECT_WIDGET: {
|
||||||
|
path: "/widget-reference/tree-single-select",
|
||||||
|
searchKey: "Tree Single Select",
|
||||||
|
},
|
||||||
ICON_BUTTON_WIDGET: {
|
ICON_BUTTON_WIDGET: {
|
||||||
path: "/widget-reference/icon-button",
|
path: "/widget-reference/icon-button",
|
||||||
searchKey: "Icon Button",
|
searchKey: "Icon Button",
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ export enum ValidationTypes {
|
||||||
OBJECT = "OBJECT",
|
OBJECT = "OBJECT",
|
||||||
ARRAY = "ARRAY",
|
ARRAY = "ARRAY",
|
||||||
OBJECT_ARRAY = "OBJECT_ARRAY",
|
OBJECT_ARRAY = "OBJECT_ARRAY",
|
||||||
|
NESTED_OBJECT_ARRAY = "NESTED_OBJECT_ARRAY",
|
||||||
DATE_ISO_STRING = "DATE_ISO_STRING",
|
DATE_ISO_STRING = "DATE_ISO_STRING",
|
||||||
IMAGE_URL = "IMAGE_URL",
|
IMAGE_URL = "IMAGE_URL",
|
||||||
FUNCTION = "FUNCTION",
|
FUNCTION = "FUNCTION",
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ import { ReactComponent as RatingIcon } from "assets/icons/widget/rating.svg";
|
||||||
import { ReactComponent as EmbedIcon } from "assets/icons/widget/embed.svg";
|
import { ReactComponent as EmbedIcon } from "assets/icons/widget/embed.svg";
|
||||||
import { ReactComponent as DividerIcon } from "assets/icons/widget/divider.svg";
|
import { ReactComponent as DividerIcon } from "assets/icons/widget/divider.svg";
|
||||||
import { ReactComponent as MenuButtonIcon } from "assets/icons/widget/menu-button.svg";
|
import { ReactComponent as MenuButtonIcon } from "assets/icons/widget/menu-button.svg";
|
||||||
|
import { ReactComponent as MultiTreeSelectIcon } from "assets/icons/widget/multi-tree-select.svg";
|
||||||
|
import { ReactComponent as SingleTreeSelectIcon } from "assets/icons/widget/single-tree-select.svg";
|
||||||
import { ReactComponent as IconButtonIcon } from "assets/icons/widget/icon-button.svg";
|
import { ReactComponent as IconButtonIcon } from "assets/icons/widget/icon-button.svg";
|
||||||
import { ReactComponent as StatboxIcon } from "assets/icons/widget/statbox.svg";
|
import { ReactComponent as StatboxIcon } from "assets/icons/widget/statbox.svg";
|
||||||
import { ReactComponent as CheckboxGroupIcon } from "assets/icons/widget/checkbox-group.svg";
|
import { ReactComponent as CheckboxGroupIcon } from "assets/icons/widget/checkbox-group.svg";
|
||||||
|
|
@ -177,6 +179,16 @@ export const WidgetIcons: {
|
||||||
<MenuButtonIcon />
|
<MenuButtonIcon />
|
||||||
</IconWrapper>
|
</IconWrapper>
|
||||||
),
|
),
|
||||||
|
TREE_SINGLE_SELECT_WIDGET: (props: IconProps) => (
|
||||||
|
<IconWrapper {...props}>
|
||||||
|
<SingleTreeSelectIcon />
|
||||||
|
</IconWrapper>
|
||||||
|
),
|
||||||
|
TREE_MULTI_SELECT_WIDGET: (props: IconProps) => (
|
||||||
|
<IconWrapper {...props}>
|
||||||
|
<MultiTreeSelectIcon />
|
||||||
|
</IconWrapper>
|
||||||
|
),
|
||||||
ICON_BUTTON_WIDGET: (props: IconProps) => (
|
ICON_BUTTON_WIDGET: (props: IconProps) => (
|
||||||
<IconWrapper {...props}>
|
<IconWrapper {...props}>
|
||||||
<IconButtonIcon />
|
<IconButtonIcon />
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,12 @@ import AudioRecorderWidget, {
|
||||||
} from "widgets/AudioRecorderWidget";
|
} from "widgets/AudioRecorderWidget";
|
||||||
|
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
import SingleSelectTreeWidget, {
|
||||||
|
CONFIG as SINGLE_SELECT_TREE_WIDGET_CONFIG,
|
||||||
|
} from "widgets/SingleSelectTreeWidget";
|
||||||
|
import MultiSelectTreeWidget, {
|
||||||
|
CONFIG as MULTI_SELECT_TREE_WIDGET_CONFIG,
|
||||||
|
} from "widgets/MultiSelectTreeWidget";
|
||||||
|
|
||||||
export const registerWidgets = () => {
|
export const registerWidgets = () => {
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
|
|
@ -135,5 +141,8 @@ export const registerWidgets = () => {
|
||||||
registerWidget(FilePickerWidgetV2, FILEPICKER_WIDGET_V2_CONFIG);
|
registerWidget(FilePickerWidgetV2, FILEPICKER_WIDGET_V2_CONFIG);
|
||||||
registerWidget(StatboxWidget, STATBOX_WIDGET_CONFIG);
|
registerWidget(StatboxWidget, STATBOX_WIDGET_CONFIG);
|
||||||
registerWidget(AudioRecorderWidget, AUDIO_RECORDER_WIDGET_CONFIG);
|
registerWidget(AudioRecorderWidget, AUDIO_RECORDER_WIDGET_CONFIG);
|
||||||
|
registerWidget(MultiSelectTreeWidget, MULTI_SELECT_TREE_WIDGET_CONFIG);
|
||||||
|
registerWidget(SingleSelectTreeWidget, SINGLE_SELECT_TREE_WIDGET_CONFIG);
|
||||||
|
|
||||||
log.debug("Widget registration took: ", performance.now() - start, "ms");
|
log.debug("Widget registration took: ", performance.now() - start, "ms");
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -314,6 +314,45 @@ export const entityDefinitions: Record<string, unknown> = {
|
||||||
isVisible: isVisible,
|
isVisible: isVisible,
|
||||||
label: "string",
|
label: "string",
|
||||||
},
|
},
|
||||||
|
//TODO: fix this after development
|
||||||
|
SINGLE_SELECT_TREE_WIDGET: {
|
||||||
|
"!doc":
|
||||||
|
"Single Select Tree is used to capture user input from a specified list of permitted inputs/Nested Inputs.",
|
||||||
|
"!url": "https://docs.appsmith.com/widget-reference/treeselect",
|
||||||
|
isVisible: isVisible,
|
||||||
|
selectedOptionValue: {
|
||||||
|
"!type": "string",
|
||||||
|
"!doc": "The value selected in a tree select dropdown",
|
||||||
|
"!url": "https://docs.appsmith.com/widget-reference/treeselect",
|
||||||
|
},
|
||||||
|
selectedOptionLabel: {
|
||||||
|
"!type": "string",
|
||||||
|
"!doc": "The selected option label in a tree select dropdown",
|
||||||
|
"!url": "https://docs.appsmith.com/widget-reference/treeselect",
|
||||||
|
},
|
||||||
|
isDisabled: "bool",
|
||||||
|
isValid: "bool",
|
||||||
|
options: "[dropdownOption]",
|
||||||
|
},
|
||||||
|
MULTI_SELECT_TREE_WIDGET: {
|
||||||
|
"!doc":
|
||||||
|
"Multi Select Tree is used to capture user inputs from a specified list of permitted inputs/Nested Inputs. A Tree Select can capture a single choice as well as multiple choices",
|
||||||
|
"!url": "https://docs.appsmith.com/widget-reference/treeselect",
|
||||||
|
isVisible: isVisible,
|
||||||
|
selectedOptionValues: {
|
||||||
|
"!type": "[string]",
|
||||||
|
"!doc": "The array of values selected in a tree select dropdown",
|
||||||
|
"!url": "https://docs.appsmith.com/widget-reference/treeselect",
|
||||||
|
},
|
||||||
|
selectedOptionLabels: {
|
||||||
|
"!type": "[string]",
|
||||||
|
"!doc": "The array of selected option labels in a tree select dropdown",
|
||||||
|
"!url": "https://docs.appsmith.com/widget-reference/treeselect",
|
||||||
|
},
|
||||||
|
isDisabled: "bool",
|
||||||
|
isValid: "bool",
|
||||||
|
options: "[dropdownOption]",
|
||||||
|
},
|
||||||
ICON_BUTTON_WIDGET: {
|
ICON_BUTTON_WIDGET: {
|
||||||
"!doc":
|
"!doc":
|
||||||
"Icon button widget is just an icon, along with all other button properties.",
|
"Icon button widget is just an icon, along with all other button properties.",
|
||||||
|
|
|
||||||
|
|
@ -114,6 +114,7 @@ export function getExpectedValue(
|
||||||
autocompleteDataType: AutocompleteDataType.OBJECT,
|
autocompleteDataType: AutocompleteDataType.OBJECT,
|
||||||
};
|
};
|
||||||
case ValidationTypes.ARRAY:
|
case ValidationTypes.ARRAY:
|
||||||
|
case ValidationTypes.NESTED_OBJECT_ARRAY:
|
||||||
if (config.params?.allowedValues) {
|
if (config.params?.allowedValues) {
|
||||||
const allowed = config.params?.allowedValues.join("' | '");
|
const allowed = config.params?.allowedValues.join("' | '");
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -272,7 +272,6 @@ const BaseButton = styled(Button)<ThemeProp & BaseStyleProps>`
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
|
|
||||||
|
|
||||||
border-radius: ${({ borderRadius }) =>
|
border-radius: ${({ borderRadius }) =>
|
||||||
borderRadius === ButtonBorderRadiusTypes.ROUNDED ? "5px" : 0};
|
borderRadius === ButtonBorderRadiusTypes.ROUNDED ? "5px" : 0};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,891 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Checkbox, Classes, Label } from "@blueprintjs/core";
|
||||||
|
import styled, { keyframes } from "styled-components";
|
||||||
|
import { Colors } from "constants/Colors";
|
||||||
|
import { createGlobalStyle } from "constants/DefaultTheme";
|
||||||
|
import {
|
||||||
|
FontStyleTypes,
|
||||||
|
TextSize,
|
||||||
|
TEXT_SIZES,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
|
|
||||||
|
export const menuItemSelectedIcon = (props: { isSelected: boolean }) => {
|
||||||
|
return <StyledCheckbox checked={props.isSelected} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TextLabelWrapper = styled.div<{
|
||||||
|
compactMode: boolean;
|
||||||
|
}>`
|
||||||
|
${(props) =>
|
||||||
|
props.compactMode ? "&&& {margin-right: 5px;}" : "width: 100%;"}
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledLabel = styled(Label)<{
|
||||||
|
$compactMode: boolean;
|
||||||
|
$labelText?: string;
|
||||||
|
$labelTextColor?: string;
|
||||||
|
$labelTextSize?: TextSize;
|
||||||
|
$labelStyle?: string;
|
||||||
|
}>`
|
||||||
|
overflow-y: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: ${(props) => (props.$compactMode ? "auto" : "100%")};
|
||||||
|
text-align: left;
|
||||||
|
color: ${(props) => props.$labelTextColor || "inherit"};
|
||||||
|
font-size: ${(props) =>
|
||||||
|
props.$labelTextSize ? TEXT_SIZES[props.$labelTextSize] : "14px"};
|
||||||
|
font-weight: ${(props) =>
|
||||||
|
props?.$labelStyle?.includes(FontStyleTypes.BOLD) ? "bold" : "normal"};
|
||||||
|
font-style: ${(props) =>
|
||||||
|
props?.$labelStyle?.includes(FontStyleTypes.ITALIC) ? "italic" : ""};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const rcSelectDropdownSlideUpIn = keyframes`
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const rcSelectDropdownSlideUpOut = keyframes`
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DropdownStyles = createGlobalStyle`
|
||||||
|
.rc-tree-select-dropdown-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-group {
|
||||||
|
color: #999;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
.rc-tree-select-item-option-state {
|
||||||
|
pointer-events: all;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-grouped {
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-content {
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-active {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-selected {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-disabled {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-empty {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom {
|
||||||
|
transition: all 0s;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-appear {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-appear.rc-tree-select-selection__choice-zoom-appear-active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-leave {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-leave.rc-tree-select-selection__choice-zoom-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-enter {
|
||||||
|
animation-duration: 0s;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
opacity: 0;
|
||||||
|
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-appear {
|
||||||
|
animation-duration: 0s;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
opacity: 0;
|
||||||
|
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-leave {
|
||||||
|
animation-duration: 0s;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
opacity: 1;
|
||||||
|
animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-enter.rc-tree-select-dropdown-slide-up-enter-active.rc-tree-select-dropdown-placement-bottomLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-appear.rc-tree-select-dropdown-slide-up-appear-active.rc-tree-select-dropdown-placement-bottomLeft {
|
||||||
|
animation-name:${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-leave.rc-tree-select-dropdown-slide-up-leave-active.rc-tree-select-dropdown-placement-bottomLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpOut};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-enter.rc-tree-select-dropdown-slide-up-enter-active.rc-tree-select-dropdown-placement-topLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-appear.rc-tree-select-dropdown-slide-up-appear-active.rc-tree-select-dropdown-placement-topLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-leave.rc-tree-select-dropdown-slide-up-leave-active.rc-tree-select-dropdown-placement-topLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpOut};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.tree-select-dropdown.single-tree-select-dropdown {
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.rc-tree-select-tree-treenode-disabled
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 5px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
direction: ltr;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #E8E8E8;
|
||||||
|
border-radius: 100%;
|
||||||
|
border-collapse: separate;
|
||||||
|
transition: all .3s;
|
||||||
|
:after{
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 52%;
|
||||||
|
display: table;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border: none;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
transform: rotate(
|
||||||
|
45deg
|
||||||
|
) scale(0) translate(-50%,-50%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
.rc-tree-select-tree-node-selected
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
:after{
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
transform: translate(-50%,-50%) scale(1);
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
opacity: 1;
|
||||||
|
content: " ";
|
||||||
|
border-radius: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.tree-select-dropdown {
|
||||||
|
min-height: 100px;
|
||||||
|
min-width: 250px !important;
|
||||||
|
position: absolute;
|
||||||
|
background: #fff;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 2px rgb(0 0 0 / 20%) !important;
|
||||||
|
&&&& .${Classes.ALIGN_LEFT} {
|
||||||
|
font-size: 16px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-left: 16px ;
|
||||||
|
.${Classes.CONTROL_INDICATOR} {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&&&& .${Classes.CONTROL} .${Classes.CONTROL_INDICATOR} {
|
||||||
|
background: white;
|
||||||
|
box-shadow: none;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: ${Colors.GEYSER};
|
||||||
|
&::before {
|
||||||
|
width: auto;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.${Classes.CONTROL} input:checked ~ .${Classes.CONTROL_INDICATOR} {
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
padding: 5px 16px;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-state {
|
||||||
|
.bp3-control.bp3-checkbox {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.rc-tree-select-tree {
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-focused:not(.rc-tree-select-tree-active-focused) {
|
||||||
|
border-color: cyan;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
list-style: none;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0 5px;
|
||||||
|
height: 34px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode .draggable {
|
||||||
|
color: #333;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-khtml-user-drag: element;
|
||||||
|
-webkit-user-drag: element;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.drop-container
|
||||||
|
> .draggable::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: inset 0 0 0 2px red;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.drop-container
|
||||||
|
~ .rc-tree-select-tree-treenode {
|
||||||
|
border-left: 2px solid chocolate;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode.drop-target {
|
||||||
|
background-color: yellowgreen;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.drop-target
|
||||||
|
~ .rc-tree-select-tree-treenode {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.filter-node
|
||||||
|
> .rc-tree-select-tree-node-content-wrapper {
|
||||||
|
color: #182026 !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 0 18px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
.rc-tree-select-tree-node-content-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 34px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
vertical-align: top;
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-checked .rc-tree-select-tree-checkbox-inner:after {
|
||||||
|
position: absolute;
|
||||||
|
display: table;
|
||||||
|
border: 2px solid #fff;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
transform: rotate(
|
||||||
|
45deg
|
||||||
|
) scale(1) translate(-50%,-50%);
|
||||||
|
opacity: 1;
|
||||||
|
transition: all .2s cubic-bezier(.12,.4,.29,1.46) .1s;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-checkbox-inner:after {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 22%;
|
||||||
|
display: table;
|
||||||
|
width: 5.71428571px;
|
||||||
|
height: 9.14285714px;
|
||||||
|
border: 2px solid #fff;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
transform: rotate(
|
||||||
|
45deg
|
||||||
|
) scale(0) translate(-50%,-50%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-indeterminate .rc-tree-select-tree-checkbox-inner:after {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: rgb(3, 179, 101) !important;
|
||||||
|
border: 0;
|
||||||
|
transform: translate(-50%,-50%) scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox:hover:after, .rc-tree-select-tree-checkbox-wrapper:hover .rc-tree-select-tree-checkbox:after {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox {
|
||||||
|
top: initial;
|
||||||
|
margin: 4px 8px 0 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-checkbox {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: #000000d9;
|
||||||
|
font-size: 14px;
|
||||||
|
font-variant: tabular-nums;
|
||||||
|
line-height: 1.5715;
|
||||||
|
list-style: none;
|
||||||
|
font-feature-settings: "tnum";
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-wrapper:hover .rc-tree-select-tree-checkbox-inner, .rc-tree-select-tree-checkbox:hover .rc-tree-select-tree-checkbox-inner, .rc-tree-select-tree-checkbox-input:focus+.rc-tree-select-tree-checkbox-inner {
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-checkbox-checked .rc-tree-select-tree-checkbox-inner {
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-inner {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
direction: ltr;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree.select-tree-checkbox-checked {
|
||||||
|
.rc-tree-select-tree-checkbox-inner {
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.single-tree-select-dropdown
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
vertical-align: -0.125em;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-attachment: scroll;
|
||||||
|
border: 0 none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-icon__customize,
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-checkbox.rc-tree-select-tree-icon__customize,
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle.rc-tree-select-tree-icon__customize {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-icon_loading {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-switcher-noop {
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-switcher_open {
|
||||||
|
background-position: -93px -56px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-switcher_close {
|
||||||
|
background-position: -75px -56px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree:not(.rc-tree-select-tree-show-line)
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
.rc-tree-select-tree-switcher-noop {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree.rc-tree-select-tree-show-line
|
||||||
|
.rc-tree-select-tree-treenode:not(:last-child)
|
||||||
|
> ul {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree.rc-tree-select-tree-show-line
|
||||||
|
.rc-tree-select-tree-treenode:not(:last-child)
|
||||||
|
> .rc-tree-select-tree-switcher-noop {
|
||||||
|
background-position: -56px -18px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree.rc-tree-select-tree-show-line
|
||||||
|
.rc-tree-select-tree-treenode:last-child
|
||||||
|
> .rc-tree-select-tree-switcher-noop {
|
||||||
|
background-position: -56px -36px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-child-tree {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-child-tree-open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-treenode-disabled
|
||||||
|
> span:not(.rc-tree-select-tree-switcher),
|
||||||
|
.rc-tree-select-tree-treenode-disabled > a,
|
||||||
|
.rc-tree-select-tree-treenode-disabled > a span {
|
||||||
|
color: #767676;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-treenode-active {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-treenode:hover {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-node-selected {
|
||||||
|
background-color: none;
|
||||||
|
box-shadow: 0 0 0 0 #ffb951;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__open {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background-position: -110px -16px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__close {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background-position: -110px 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__docu {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background-position: -110px -32px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__customize {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-title {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-indent {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: bottom;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-indent-unit {
|
||||||
|
width: 25px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TreeSelectContainer = styled.div<{
|
||||||
|
compactMode: boolean;
|
||||||
|
allowClear: boolean;
|
||||||
|
}>`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: ${(props) => (props.compactMode ? "row" : "column")};
|
||||||
|
align-items: ${(props) => (props.compactMode ? "center" : "left")};
|
||||||
|
|
||||||
|
label.tree-select-label {
|
||||||
|
margin-bottom: ${(props) => (props.compactMode ? "0px" : "5px")};
|
||||||
|
margin-right: ${(props) => (props.compactMode ? "10px" : "0px")};
|
||||||
|
}
|
||||||
|
.rc-tree-select {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 1 1;
|
||||||
|
.rc-tree-select-selection-placeholder {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 11px;
|
||||||
|
left: 11px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
transition: all 0.3s;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #bfbfbf;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
pointer-events: none;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search-input {
|
||||||
|
appearance: none;
|
||||||
|
&::-webkit-search-cancel-button {
|
||||||
|
display: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-overflow-item-suffix {
|
||||||
|
position: relative !important;
|
||||||
|
left: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
input {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow.rc-tree-select-loading {
|
||||||
|
.rc-tree-select-arrow-icon {
|
||||||
|
&::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: 2px solid #999;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
transform: none;
|
||||||
|
margin-top: 4px;
|
||||||
|
animation: rcSelectLoadingIcon 0.5s infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-single .rc-tree-select-selector {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 1px;
|
||||||
|
padding-right: 20px;
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid rgb(231, 231, 231);
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 100%;
|
||||||
|
transition: border-color 0.15s ease-in-out 0s,
|
||||||
|
box-shadow 0.15s ease-in-out 0s;
|
||||||
|
background-color: white;
|
||||||
|
height: 100%;
|
||||||
|
.rc-tree-select-selection-search {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
appearance: none;
|
||||||
|
&::-webkit-search-cancel-button {
|
||||||
|
display: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
font-family: system-ui;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-item {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 11px;
|
||||||
|
left: 11px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
transition: all 0.3s;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #231f20;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
pointer-events: none;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-multiple {
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 1px;
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid rgb(231, 231, 231);
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 100%;
|
||||||
|
transition: border-color 0.15s ease-in-out 0s,
|
||||||
|
box-shadow 0.15s ease-in-out 0s;
|
||||||
|
background-color: white;
|
||||||
|
.rc-tree-select-selection-item {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid rgb(208, 215, 221);
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 3px 2px;
|
||||||
|
max-width: 273.926px;
|
||||||
|
height: 24px;
|
||||||
|
color: #182026;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: none;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
min-height: 20px;
|
||||||
|
min-width: 20px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-item-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-overflow {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-overflow-item {
|
||||||
|
flex: none;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search {
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search-input {
|
||||||
|
padding: 1px;
|
||||||
|
font-family: system-ui;
|
||||||
|
width: 5px;
|
||||||
|
margin: 0px;
|
||||||
|
display: flex;
|
||||||
|
height: 26px;
|
||||||
|
flex: 1 1 0%;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search-mirror {
|
||||||
|
padding: 1px;
|
||||||
|
font-family: system-ui;
|
||||||
|
width: 5px;
|
||||||
|
margin: 0px;
|
||||||
|
display: flex;
|
||||||
|
height: 26px;
|
||||||
|
flex: 1 1 0%;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
white-space: nowrap;
|
||||||
|
position: none;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-item-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
margin-right: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-wrap: normal;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-allow-clear {
|
||||||
|
.rc-tree-select-clear {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
right: 25px;
|
||||||
|
top: -1px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
z-index: -1;
|
||||||
|
.rc-tree-select-clear-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-allow-clear.rc-tree-select-focused {
|
||||||
|
.rc-tree-select-clear {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow.rc-tree-select-multiple {
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
padding-right: ${({ allowClear }) => (allowClear ? "40px" : "20px")};
|
||||||
|
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid rgb(231, 231, 231);
|
||||||
|
border-radius: 0px;
|
||||||
|
height: inherit;
|
||||||
|
width: 100%;
|
||||||
|
transition: border-color 0.15s ease-in-out 0s,
|
||||||
|
box-shadow 0.15s ease-in-out 0s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow {
|
||||||
|
.rc-tree-select-arrow {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.rc-tree-select-arrow-icon {
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
border: 5px solid transparent;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
display: inline-block;
|
||||||
|
border-top-color: #999;
|
||||||
|
transform: translateY(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow.rc-tree-select-focused {
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
border: 1px solid rgb(128, 189, 255);
|
||||||
|
outline: 0px;
|
||||||
|
box-shadow: rgba(0, 123, 255, 0.25) 0px 0px 0px 0.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const StyledCheckbox = styled(Checkbox)`
|
||||||
|
&&.${Classes.CHECKBOX}.${Classes.CONTROL} {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const inputIcon = (): JSX.Element => (
|
||||||
|
<svg data-icon="chevron-down" height="16" viewBox="0 0 16 16" width="16">
|
||||||
|
<desc>chevron-down</desc>
|
||||||
|
<path
|
||||||
|
d="M12 5c-.28 0-.53.11-.71.29L8 8.59l-3.29-3.3a1.003 1.003 0 00-1.42 1.42l4 4c.18.18.43.29.71.29s.53-.11.71-.29l4-4A1.003 1.003 0 0012 5z"
|
||||||
|
fillRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
191
app/client/src/widgets/MultiSelectTreeWidget/component/index.tsx
Normal file
191
app/client/src/widgets/MultiSelectTreeWidget/component/index.tsx
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
import React, {
|
||||||
|
ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import TreeSelect, { TreeSelectProps as SelectProps } from "rc-tree-select";
|
||||||
|
import {
|
||||||
|
TreeSelectContainer,
|
||||||
|
DropdownStyles,
|
||||||
|
inputIcon,
|
||||||
|
StyledLabel,
|
||||||
|
TextLabelWrapper,
|
||||||
|
} from "./index.styled";
|
||||||
|
import "rc-tree-select/assets/index.less";
|
||||||
|
import { DefaultValueType } from "rc-tree-select/lib/interface";
|
||||||
|
import { TreeNodeProps } from "rc-tree-select/lib/TreeNode";
|
||||||
|
import { CheckedStrategy } from "rc-tree-select/lib/utils/strategyUtil";
|
||||||
|
import {
|
||||||
|
CANVAS_CLASSNAME,
|
||||||
|
MODAL_PORTAL_CLASSNAME,
|
||||||
|
TextSize,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
|
import { Classes } from "@blueprintjs/core";
|
||||||
|
export interface TreeSelectProps
|
||||||
|
extends Required<
|
||||||
|
Pick<
|
||||||
|
SelectProps,
|
||||||
|
| "disabled"
|
||||||
|
| "options"
|
||||||
|
| "placeholder"
|
||||||
|
| "loading"
|
||||||
|
| "dropdownStyle"
|
||||||
|
| "allowClear"
|
||||||
|
>
|
||||||
|
> {
|
||||||
|
value?: DefaultValueType;
|
||||||
|
onChange: (value?: DefaultValueType, labelList?: ReactNode[]) => void;
|
||||||
|
expandAll: boolean;
|
||||||
|
mode: CheckedStrategy;
|
||||||
|
labelText?: string;
|
||||||
|
labelTextColor?: string;
|
||||||
|
labelTextSize?: TextSize;
|
||||||
|
labelStyle?: string;
|
||||||
|
compactMode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSvg = (style = {}) => (
|
||||||
|
<i
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
display: "inline-flex",
|
||||||
|
width: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
fill="none"
|
||||||
|
height="10"
|
||||||
|
style={{ verticalAlign: "-.125em", ...style }}
|
||||||
|
viewBox="0 0 10 10"
|
||||||
|
width="10"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M2.5 9L7.5 5L2.5 1L2.5 9Z"
|
||||||
|
fill="#090707"
|
||||||
|
ill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</i>
|
||||||
|
);
|
||||||
|
|
||||||
|
const switcherIcon = (treeNode: TreeNodeProps) => {
|
||||||
|
if (treeNode.isLeaf) {
|
||||||
|
return (
|
||||||
|
<i
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
backgroundColor: "white",
|
||||||
|
display: "inline-flex",
|
||||||
|
width: "10px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return getSvg({ transform: `rotate(${treeNode.expanded ? 90 : 0}deg)` });
|
||||||
|
};
|
||||||
|
|
||||||
|
function MultiTreeSelectComponent({
|
||||||
|
allowClear,
|
||||||
|
compactMode,
|
||||||
|
disabled,
|
||||||
|
dropdownStyle,
|
||||||
|
expandAll,
|
||||||
|
labelStyle,
|
||||||
|
labelText,
|
||||||
|
labelTextColor,
|
||||||
|
labelTextSize,
|
||||||
|
loading,
|
||||||
|
mode,
|
||||||
|
onChange,
|
||||||
|
options,
|
||||||
|
placeholder,
|
||||||
|
value,
|
||||||
|
}: TreeSelectProps): JSX.Element {
|
||||||
|
const [key, setKey] = useState(Math.random());
|
||||||
|
const _menu = useRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
// treeDefaultExpandAll is uncontrolled after first render,
|
||||||
|
// using this to force render to respond to changes in expandAll
|
||||||
|
useEffect(() => {
|
||||||
|
setKey(Math.random());
|
||||||
|
}, [expandAll]);
|
||||||
|
|
||||||
|
const getDropdownPosition = useCallback(() => {
|
||||||
|
const node = _menu.current;
|
||||||
|
if (Boolean(node?.closest(`.${MODAL_PORTAL_CLASSNAME}`))) {
|
||||||
|
return document.querySelector(
|
||||||
|
`.${MODAL_PORTAL_CLASSNAME}`,
|
||||||
|
) as HTMLElement;
|
||||||
|
}
|
||||||
|
return document.querySelector(`.${CANVAS_CLASSNAME}`) as HTMLElement;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const onClear = useCallback(() => onChange([], []), []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TreeSelectContainer
|
||||||
|
allowClear={allowClear}
|
||||||
|
compactMode={compactMode}
|
||||||
|
ref={_menu as React.RefObject<HTMLDivElement>}
|
||||||
|
>
|
||||||
|
<DropdownStyles />
|
||||||
|
{labelText && (
|
||||||
|
<TextLabelWrapper compactMode={compactMode}>
|
||||||
|
<StyledLabel
|
||||||
|
$compactMode={compactMode}
|
||||||
|
$labelStyle={labelStyle}
|
||||||
|
$labelText={labelText}
|
||||||
|
$labelTextColor={labelTextColor}
|
||||||
|
$labelTextSize={labelTextSize}
|
||||||
|
className={`tree-select-label ${
|
||||||
|
loading ? Classes.SKELETON : Classes.TEXT_OVERFLOW_ELLIPSIS
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{labelText}
|
||||||
|
</StyledLabel>
|
||||||
|
</TextLabelWrapper>
|
||||||
|
)}
|
||||||
|
<TreeSelect
|
||||||
|
allowClear={allowClear}
|
||||||
|
animation="slide-up"
|
||||||
|
choiceTransitionName="rc-tree-select-selection__choice-zoom"
|
||||||
|
className="rc-tree-select"
|
||||||
|
disabled={disabled}
|
||||||
|
dropdownClassName="tree-select-dropdown"
|
||||||
|
dropdownStyle={dropdownStyle}
|
||||||
|
getPopupContainer={getDropdownPosition}
|
||||||
|
inputIcon={inputIcon}
|
||||||
|
key={key}
|
||||||
|
loading={loading}
|
||||||
|
maxTagCount={"responsive"}
|
||||||
|
maxTagPlaceholder={(e) => `+${e.length} more`}
|
||||||
|
multiple
|
||||||
|
notFoundContent="No item Found"
|
||||||
|
onChange={onChange}
|
||||||
|
onClear={onClear}
|
||||||
|
placeholder={placeholder}
|
||||||
|
showArrow
|
||||||
|
showCheckedStrategy={mode}
|
||||||
|
showSearch
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
switcherIcon={switcherIcon}
|
||||||
|
transitionName="rc-tree-select-dropdown-slide-up"
|
||||||
|
treeCheckable={
|
||||||
|
<span className={`rc-tree-select-tree-checkbox-inner`} />
|
||||||
|
}
|
||||||
|
treeData={options}
|
||||||
|
treeDefaultExpandAll={expandAll}
|
||||||
|
treeIcon
|
||||||
|
treeNodeFilterProp="label"
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
</TreeSelectContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MultiTreeSelectComponent;
|
||||||
1
app/client/src/widgets/MultiSelectTreeWidget/icon.svg
Normal file
1
app/client/src/widgets/MultiSelectTreeWidget/icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.75" y="0.75" width="18.5" height="6.5" stroke="#EAEAEA" stroke-width="1.5"/><path d="M7.99985 10.05L14.9998 10.05V11.55L7.99985 11.55L7.99985 10.05Z" fill="#EAEAEA"/><path d="M7.99985 14.75H13.9998V16.25L7.99985 16.25L7.99985 14.75Z" fill="#EAEAEA"/><path d="M5.99985 10.5L2.99985 10.5L4.49985 12L5.99985 10.5Z" fill="#EAEAEA"/><path d="M6 15L3 15L4.5 16.5L6 15Z" fill="#EAEAEA"/><path fill-rule="evenodd" clip-rule="evenodd" d="M0 6.5V20H18V6.5H0ZM1.5 18.5V8H16.5V18.5H1.5Z" fill="#EAEAEA"/><path d="M3 3.25H11V4.75H3V3.25Z" fill="#EAEAEA"/><path d="M12 3.25H17V4.75H12V3.25Z" fill="#EAEAEA"/></svg>
|
||||||
|
After Width: | Height: | Size: 707 B |
51
app/client/src/widgets/MultiSelectTreeWidget/index.ts
Normal file
51
app/client/src/widgets/MultiSelectTreeWidget/index.ts
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
import Widget from "./widget";
|
||||||
|
import IconSVG from "./icon.svg";
|
||||||
|
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
|
||||||
|
|
||||||
|
export const CONFIG = {
|
||||||
|
type: Widget.getWidgetType(),
|
||||||
|
name: "Multi Select Tree",
|
||||||
|
iconSVG: IconSVG,
|
||||||
|
needsMeta: true,
|
||||||
|
defaults: {
|
||||||
|
rows: 1.72 * GRID_DENSITY_MIGRATION_V1,
|
||||||
|
columns: 4 * GRID_DENSITY_MIGRATION_V1,
|
||||||
|
mode: "SHOW_ALL",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Blue",
|
||||||
|
value: "BLUE",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Dark Blue",
|
||||||
|
value: "DARK BLUE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Light Blue",
|
||||||
|
value: "LIGHT BLUE",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ label: "Green", value: "GREEN" },
|
||||||
|
{ label: "Red", value: "RED" },
|
||||||
|
],
|
||||||
|
widgetName: "MultiSelectTree",
|
||||||
|
defaultOptionValue: ["GREEN"],
|
||||||
|
version: 1,
|
||||||
|
isVisible: true,
|
||||||
|
isRequired: false,
|
||||||
|
isDisabled: false,
|
||||||
|
allowClear: false,
|
||||||
|
expandAll: false,
|
||||||
|
placeholderText: "select option(s)",
|
||||||
|
labelText: "Label",
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
derived: Widget.getDerivedPropertiesMap(),
|
||||||
|
default: Widget.getDefaultPropertiesMap(),
|
||||||
|
meta: Widget.getMetaPropertiesMap(),
|
||||||
|
config: Widget.getPropertyPaneConfig(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Widget;
|
||||||
465
app/client/src/widgets/MultiSelectTreeWidget/widget/index.tsx
Normal file
465
app/client/src/widgets/MultiSelectTreeWidget/widget/index.tsx
Normal file
|
|
@ -0,0 +1,465 @@
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
import BaseWidget, { WidgetProps, WidgetState } from "widgets/BaseWidget";
|
||||||
|
import { TextSize, WidgetType } from "constants/WidgetConstants";
|
||||||
|
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
||||||
|
import { isArray, findIndex } from "lodash";
|
||||||
|
import {
|
||||||
|
ValidationResponse,
|
||||||
|
ValidationTypes,
|
||||||
|
} from "constants/WidgetValidation";
|
||||||
|
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
||||||
|
import { DefaultValueType } from "rc-select/lib/interface/generator";
|
||||||
|
import { Layers } from "constants/Layers";
|
||||||
|
import { CheckedStrategy } from "rc-tree-select/lib/utils/strategyUtil";
|
||||||
|
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
|
||||||
|
import { AutocompleteDataType } from "utils/autocomplete/TernServer";
|
||||||
|
import MultiTreeSelectComponent from "../component";
|
||||||
|
|
||||||
|
function defaultOptionValueValidation(value: unknown): ValidationResponse {
|
||||||
|
let values: string[] = [];
|
||||||
|
if (typeof value === "string") {
|
||||||
|
try {
|
||||||
|
values = JSON.parse(value);
|
||||||
|
if (!Array.isArray(values)) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
values = value.length ? value.split(",") : [];
|
||||||
|
if (values.length > 0) {
|
||||||
|
values = values.map((_v: string) => _v.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
values = Array.from(new Set(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
isValid: true,
|
||||||
|
parsed: values,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
class MultiSelectTreeWidget extends BaseWidget<
|
||||||
|
MultiSelectTreeWidgetProps,
|
||||||
|
WidgetState
|
||||||
|
> {
|
||||||
|
static getPropertyPaneConfig() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
sectionName: "General",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
helpText: "Mode to Display options",
|
||||||
|
propertyName: "mode",
|
||||||
|
label: "Mode",
|
||||||
|
controlType: "DROP_DOWN",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Display only parent items",
|
||||||
|
value: "SHOW_PARENT",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Display only child items",
|
||||||
|
value: "SHOW_CHILD",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Display all items",
|
||||||
|
value: "SHOW_ALL",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText:
|
||||||
|
"Allows users to select multiple options. Values must be unique",
|
||||||
|
propertyName: "options",
|
||||||
|
label: "Options",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter option value",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
isJSConvertible: false,
|
||||||
|
validation: {
|
||||||
|
type: ValidationTypes.NESTED_OBJECT_ARRAY,
|
||||||
|
params: {
|
||||||
|
unique: ["value"],
|
||||||
|
default: [],
|
||||||
|
children: {
|
||||||
|
type: ValidationTypes.OBJECT,
|
||||||
|
params: {
|
||||||
|
allowedKeys: [
|
||||||
|
{
|
||||||
|
name: "label",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "children",
|
||||||
|
type: ValidationTypes.ARRAY,
|
||||||
|
required: false,
|
||||||
|
params: {
|
||||||
|
children: {
|
||||||
|
type: ValidationTypes.OBJECT,
|
||||||
|
params: {
|
||||||
|
allowedKeys: [
|
||||||
|
{
|
||||||
|
name: "label",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
evaluationSubstitutionType:
|
||||||
|
EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Selects the option with value by default",
|
||||||
|
propertyName: "defaultOptionValue",
|
||||||
|
label: "Default Value",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter option value",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: {
|
||||||
|
type: ValidationTypes.FUNCTION,
|
||||||
|
params: {
|
||||||
|
fn: defaultOptionValueValidation,
|
||||||
|
expected: {
|
||||||
|
type: "Array of values",
|
||||||
|
example: `['value1', 'value2']`,
|
||||||
|
autocompleteDataType: AutocompleteDataType.ARRAY,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Label Text",
|
||||||
|
propertyName: "labelText",
|
||||||
|
label: "Label Text",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter Label text",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Input Place Holder",
|
||||||
|
propertyName: "placeholderText",
|
||||||
|
label: "Placeholder",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter placeholder text",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Controls the visibility of the widget",
|
||||||
|
propertyName: "isVisible",
|
||||||
|
label: "Visible",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "isDisabled",
|
||||||
|
label: "Disabled",
|
||||||
|
helpText: "Disables input to this widget",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "isRequired",
|
||||||
|
label: "Required",
|
||||||
|
helpText: "Makes input to the widget mandatory",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "allowClear",
|
||||||
|
label: "Clear all Selections",
|
||||||
|
helpText: "Enables Icon to clear all Selections",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "expandAll",
|
||||||
|
label: "Expand all by default",
|
||||||
|
helpText: "Expand All nested options",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sectionName: "Styles",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
propertyName: "labelTextColor",
|
||||||
|
label: "Label Text Color",
|
||||||
|
controlType: "COLOR_PICKER",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "labelTextSize",
|
||||||
|
label: "Label Text Size",
|
||||||
|
controlType: "DROP_DOWN",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Heading 1",
|
||||||
|
value: "HEADING1",
|
||||||
|
subText: "24px",
|
||||||
|
icon: "HEADING_ONE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Heading 2",
|
||||||
|
value: "HEADING2",
|
||||||
|
subText: "18px",
|
||||||
|
icon: "HEADING_TWO",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Heading 3",
|
||||||
|
value: "HEADING3",
|
||||||
|
subText: "16px",
|
||||||
|
icon: "HEADING_THREE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Paragraph",
|
||||||
|
value: "PARAGRAPH",
|
||||||
|
subText: "14px",
|
||||||
|
icon: "PARAGRAPH",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Paragraph 2",
|
||||||
|
value: "PARAGRAPH2",
|
||||||
|
subText: "12px",
|
||||||
|
icon: "PARAGRAPH_TWO",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "labelStyle",
|
||||||
|
label: "Label Font Style",
|
||||||
|
controlType: "BUTTON_TABS",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
icon: "BOLD_FONT",
|
||||||
|
value: "BOLD",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "ITALICS_FONT",
|
||||||
|
value: "ITALIC",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sectionName: "Actions",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
helpText: "Triggers an action when a user selects an option",
|
||||||
|
propertyName: "onOptionChange",
|
||||||
|
label: "onOptionChange",
|
||||||
|
controlType: "ACTION_SELECTOR",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedPropertiesMap() {
|
||||||
|
return {
|
||||||
|
selectedOptionLabels: `{{ this.selectedLabel }}`,
|
||||||
|
selectedOptionValues:
|
||||||
|
'{{ this.selectedOptionValueArr.filter((o) => JSON.stringify(this.options).match(new RegExp(`"value":"${o}"`, "g")) )}}',
|
||||||
|
isValid: `{{ this.isRequired ? this.selectedOptionValues?.length > 0 : true}}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDefaultPropertiesMap(): Record<string, string> {
|
||||||
|
return {
|
||||||
|
selectedOptionValueArr: "defaultOptionValue",
|
||||||
|
selectedLabel: "defaultOptionValue",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMetaPropertiesMap(): Record<string, any> {
|
||||||
|
return {
|
||||||
|
selectedOptionValueArr: undefined,
|
||||||
|
selectedLabel: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
getPageView() {
|
||||||
|
const options =
|
||||||
|
isArray(this.props.options) &&
|
||||||
|
!this.props.__evaluation__?.errors.options.length
|
||||||
|
? this.props.options
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const values = isArray(this.props.selectedOptionValueArr)
|
||||||
|
? this.props.selectedOptionValueArr
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const filteredValue = this.filterValues(values);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<MultiTreeSelectComponent
|
||||||
|
allowClear={this.props.allowClear}
|
||||||
|
compactMode={
|
||||||
|
!(
|
||||||
|
(this.props.bottomRow - this.props.topRow) /
|
||||||
|
GRID_DENSITY_MIGRATION_V1 >
|
||||||
|
1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
disabled={this.props.isDisabled ?? false}
|
||||||
|
dropdownStyle={{
|
||||||
|
zIndex: Layers.dropdownModalWidget,
|
||||||
|
}}
|
||||||
|
expandAll={this.props.expandAll}
|
||||||
|
labelStyle={this.props.labelStyle}
|
||||||
|
labelText={this.props.labelText}
|
||||||
|
labelTextColor={this.props.labelTextColor}
|
||||||
|
labelTextSize={this.props.labelTextSize}
|
||||||
|
loading={this.props.isLoading}
|
||||||
|
mode={this.props.mode}
|
||||||
|
onChange={this.onOptionChange}
|
||||||
|
options={options}
|
||||||
|
placeholder={this.props.placeholderText as string}
|
||||||
|
value={filteredValue}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onOptionChange = (value?: DefaultValueType, labelList?: ReactNode[]) => {
|
||||||
|
this.props.updateWidgetMetaProperty("selectedLabel", labelList, {
|
||||||
|
triggerPropertyName: "onOptionChange",
|
||||||
|
dynamicString: this.props.onOptionChange,
|
||||||
|
event: {
|
||||||
|
type: EventType.ON_OPTION_CHANGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.updateWidgetMetaProperty("selectedOptionValueArr", value, {
|
||||||
|
triggerPropertyName: "onOptionChange",
|
||||||
|
dynamicString: this.props.onOptionChange,
|
||||||
|
event: {
|
||||||
|
type: EventType.ON_OPTION_CHANGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
flat(array: DropdownOption[]) {
|
||||||
|
let result: { value: string }[] = [];
|
||||||
|
array.forEach((a) => {
|
||||||
|
result.push({ value: a.value });
|
||||||
|
if (Array.isArray(a.children)) {
|
||||||
|
result = result.concat(this.flat(a.children));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterValues(values: string[] | undefined) {
|
||||||
|
const options = this.props.options
|
||||||
|
? this.flat(this.props.options as DropdownOption[])
|
||||||
|
: [];
|
||||||
|
if (isArray(values)) {
|
||||||
|
return values.filter((o) => {
|
||||||
|
const index = findIndex(options, { value: o });
|
||||||
|
return index > -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getWidgetType(): WidgetType {
|
||||||
|
return "MULTI_SELECT_TREE_WIDGET";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropdownOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
children?: DropdownOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MultiSelectTreeWidgetProps extends WidgetProps {
|
||||||
|
placeholderText?: string;
|
||||||
|
selectedIndexArr?: number[];
|
||||||
|
options?: DropdownOption[];
|
||||||
|
onOptionChange: string;
|
||||||
|
defaultOptionValue: string[];
|
||||||
|
isRequired: boolean;
|
||||||
|
isLoading: boolean;
|
||||||
|
allowClear: boolean;
|
||||||
|
labelText?: string;
|
||||||
|
selectedLabel: string[];
|
||||||
|
selectedOptionValueArr: string[];
|
||||||
|
selectedOptionValues: string[];
|
||||||
|
selectedOptionLabels: string[];
|
||||||
|
expandAll: boolean;
|
||||||
|
mode: CheckedStrategy;
|
||||||
|
labelTextColor?: string;
|
||||||
|
labelTextSize?: TextSize;
|
||||||
|
labelStyle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MultiSelectTreeWidget;
|
||||||
|
|
@ -48,13 +48,13 @@ function MultiSelectComponent({
|
||||||
const [isSelectAll, setIsSelectAll] = useState(false);
|
const [isSelectAll, setIsSelectAll] = useState(false);
|
||||||
const _menu = useRef<HTMLElement | null>(null);
|
const _menu = useRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
const getDropdownPosition = useCallback((node: HTMLElement | null) => {
|
const getDropdownPosition = useCallback(() => {
|
||||||
|
const node = _menu.current;
|
||||||
if (Boolean(node?.closest(`.${MODAL_PORTAL_CLASSNAME}`))) {
|
if (Boolean(node?.closest(`.${MODAL_PORTAL_CLASSNAME}`))) {
|
||||||
return document.querySelector(
|
return document.querySelector(
|
||||||
`.${MODAL_PORTAL_CLASSNAME}`,
|
`.${MODAL_PORTAL_CLASSNAME}`,
|
||||||
) as HTMLElement;
|
) as HTMLElement;
|
||||||
}
|
}
|
||||||
// TODO: Use generateClassName func.
|
|
||||||
return document.querySelector(`.${CANVAS_CLASSNAME}`) as HTMLElement;
|
return document.querySelector(`.${CANVAS_CLASSNAME}`) as HTMLElement;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
@ -129,7 +129,7 @@ function MultiSelectComponent({
|
||||||
dropdownRender={dropdownRender}
|
dropdownRender={dropdownRender}
|
||||||
dropdownStyle={dropdownStyle}
|
dropdownStyle={dropdownStyle}
|
||||||
filterOption={serverSideFiltering ? false : filterOption}
|
filterOption={serverSideFiltering ? false : filterOption}
|
||||||
getPopupContainer={() => getDropdownPosition(_menu.current)}
|
getPopupContainer={getDropdownPosition}
|
||||||
inputIcon={inputIcon}
|
inputIcon={inputIcon}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
maxTagCount={"responsive"}
|
maxTagCount={"responsive"}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,888 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Checkbox, Classes, Label } from "@blueprintjs/core";
|
||||||
|
import styled, { keyframes } from "styled-components";
|
||||||
|
import { Colors } from "constants/Colors";
|
||||||
|
import { createGlobalStyle } from "constants/DefaultTheme";
|
||||||
|
import {
|
||||||
|
FontStyleTypes,
|
||||||
|
TextSize,
|
||||||
|
TEXT_SIZES,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
|
|
||||||
|
export const menuItemSelectedIcon = (props: { isSelected: boolean }) => {
|
||||||
|
return <StyledCheckbox checked={props.isSelected} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TextLabelWrapper = styled.div<{
|
||||||
|
compactMode: boolean;
|
||||||
|
}>`
|
||||||
|
${(props) =>
|
||||||
|
props.compactMode ? "&&& {margin-right: 5px;}" : "width: 100%;"}
|
||||||
|
display: flex;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const StyledLabel = styled(Label)<{
|
||||||
|
$compactMode: boolean;
|
||||||
|
$labelText?: string;
|
||||||
|
$labelTextColor?: string;
|
||||||
|
$labelTextSize?: TextSize;
|
||||||
|
$labelStyle?: string;
|
||||||
|
}>`
|
||||||
|
overflow-y: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: ${(props) => (props.$compactMode ? "auto" : "100%")};
|
||||||
|
text-align: left;
|
||||||
|
color: ${(props) => props.$labelTextColor || "inherit"};
|
||||||
|
font-size: ${(props) =>
|
||||||
|
props.$labelTextSize ? TEXT_SIZES[props.$labelTextSize] : "14px"};
|
||||||
|
font-weight: ${(props) =>
|
||||||
|
props?.$labelStyle?.includes(FontStyleTypes.BOLD) ? "bold" : "normal"};
|
||||||
|
font-style: ${(props) =>
|
||||||
|
props?.$labelStyle?.includes(FontStyleTypes.ITALIC) ? "italic" : ""};
|
||||||
|
`;
|
||||||
|
|
||||||
|
const rcSelectDropdownSlideUpIn = keyframes`
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const rcSelectDropdownSlideUpOut = keyframes`
|
||||||
|
0% {
|
||||||
|
opacity: 1;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
transform-origin: 0% 0%;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const DropdownStyles = createGlobalStyle`
|
||||||
|
.rc-tree-select-dropdown-hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-group {
|
||||||
|
color: #999;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
.rc-tree-select-item-option-state {
|
||||||
|
pointer-events: all;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-grouped {
|
||||||
|
padding-left: 24px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-content {
|
||||||
|
flex: 1 1 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-active {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-selected {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-disabled {
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-empty {
|
||||||
|
text-align: center;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom {
|
||||||
|
transition: all 0s;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-appear {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-appear.rc-tree-select-selection__choice-zoom-appear-active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-leave {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection__choice-zoom-leave.rc-tree-select-selection__choice-zoom-leave-active {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-enter {
|
||||||
|
animation-duration: 0s;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
opacity: 0;
|
||||||
|
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-appear {
|
||||||
|
animation-duration: 0s;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
opacity: 0;
|
||||||
|
animation-timing-function: cubic-bezier(0.08, 0.82, 0.17, 1);
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-leave {
|
||||||
|
animation-duration: 0s;
|
||||||
|
animation-fill-mode: both;
|
||||||
|
transform-origin: 0 0;
|
||||||
|
opacity: 1;
|
||||||
|
animation-timing-function: cubic-bezier(0.6, 0.04, 0.98, 0.34);
|
||||||
|
animation-play-state: paused;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-enter.rc-tree-select-dropdown-slide-up-enter-active.rc-tree-select-dropdown-placement-bottomLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-appear.rc-tree-select-dropdown-slide-up-appear-active.rc-tree-select-dropdown-placement-bottomLeft {
|
||||||
|
animation-name:${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-leave.rc-tree-select-dropdown-slide-up-leave-active.rc-tree-select-dropdown-placement-bottomLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpOut};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-enter.rc-tree-select-dropdown-slide-up-enter-active.rc-tree-select-dropdown-placement-topLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-appear.rc-tree-select-dropdown-slide-up-appear-active.rc-tree-select-dropdown-placement-topLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpIn};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
.rc-tree-select-dropdown-slide-up-leave.rc-tree-select-dropdown-slide-up-leave-active.rc-tree-select-dropdown-placement-topLeft {
|
||||||
|
animation-name: ${rcSelectDropdownSlideUpOut};
|
||||||
|
animation-play-state: running;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.tree-select-dropdown.single-tree-select-dropdown {
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.rc-tree-select-tree-treenode-disabled
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 5px;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
direction: ltr;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #E8E8E8;
|
||||||
|
border-radius: 100%;
|
||||||
|
border-collapse: separate;
|
||||||
|
transition: all .3s;
|
||||||
|
:after{
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 52%;
|
||||||
|
display: table;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
border: none;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
transform: rotate(
|
||||||
|
45deg
|
||||||
|
) scale(0) translate(-50%,-50%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
.rc-tree-select-tree-node-selected
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
:after{
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
transform: translate(-50%,-50%) scale(1);
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
opacity: 1;
|
||||||
|
content: " ";
|
||||||
|
border-radius: 100%;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
.tree-select-dropdown {
|
||||||
|
min-height: 100px;
|
||||||
|
min-width: 250px !important;
|
||||||
|
position: absolute;
|
||||||
|
background: #fff;
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 0px;
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 12px;
|
||||||
|
background: white;
|
||||||
|
box-shadow: 0 0 2px rgb(0 0 0 / 20%) !important;
|
||||||
|
&&&& .${Classes.ALIGN_LEFT} {
|
||||||
|
font-size: 16px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
margin-left: 16px ;
|
||||||
|
.${Classes.CONTROL_INDICATOR} {
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&&&& .${Classes.CONTROL} .${Classes.CONTROL_INDICATOR} {
|
||||||
|
background: white;
|
||||||
|
box-shadow: none;
|
||||||
|
border-width: 2px;
|
||||||
|
border-style: solid;
|
||||||
|
border-color: ${Colors.GEYSER};
|
||||||
|
&::before {
|
||||||
|
width: auto;
|
||||||
|
height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.${Classes.CONTROL} input:checked ~ .${Classes.CONTROL_INDICATOR} {
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
color: rgb(255, 255, 255);
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
box-shadow: none;
|
||||||
|
outline: none !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5;
|
||||||
|
padding: 5px 16px;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.rc-tree-select-item-option-state {
|
||||||
|
.bp3-control.bp3-checkbox {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.rc-tree-select-tree {
|
||||||
|
margin: 0;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-focused:not(.rc-tree-select-tree-active-focused) {
|
||||||
|
border-color: cyan;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
line-height: 24px;
|
||||||
|
white-space: nowrap;
|
||||||
|
list-style: none;
|
||||||
|
outline: 0;
|
||||||
|
padding: 0 5px;
|
||||||
|
height: 34px;
|
||||||
|
align-items: center;
|
||||||
|
display: flex !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode .draggable {
|
||||||
|
color: #333;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
-khtml-user-drag: element;
|
||||||
|
-webkit-user-drag: element;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.drop-container
|
||||||
|
> .draggable::after {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
box-shadow: inset 0 0 0 2px red;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.drop-container
|
||||||
|
~ .rc-tree-select-tree-treenode {
|
||||||
|
border-left: 2px solid chocolate;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode.drop-target {
|
||||||
|
background-color: yellowgreen;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.drop-target
|
||||||
|
~ .rc-tree-select-tree-treenode {
|
||||||
|
border-left: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode.filter-node
|
||||||
|
> .rc-tree-select-tree-node-content-wrapper {
|
||||||
|
color: #182026 !important;
|
||||||
|
font-weight: bold !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree .rc-tree-select-tree-treenode ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0 0 0 18px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
.rc-tree-select-tree-node-content-wrapper {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 34px;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
vertical-align: top;
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-checked .rc-tree-select-tree-checkbox-inner:after {
|
||||||
|
position: absolute;
|
||||||
|
display: table;
|
||||||
|
border: 2px solid #fff;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
transform: rotate(
|
||||||
|
45deg
|
||||||
|
) scale(1) translate(-50%,-50%);
|
||||||
|
opacity: 1;
|
||||||
|
transition: all .2s cubic-bezier(.12,.4,.29,1.46) .1s;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-checkbox-inner:after {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 22%;
|
||||||
|
display: table;
|
||||||
|
width: 5.71428571px;
|
||||||
|
height: 9.14285714px;
|
||||||
|
border: 2px solid #fff;
|
||||||
|
border-top: 0;
|
||||||
|
border-left: 0;
|
||||||
|
transform: rotate(
|
||||||
|
45deg
|
||||||
|
) scale(0) translate(-50%,-50%);
|
||||||
|
opacity: 0;
|
||||||
|
transition: all .1s cubic-bezier(.71,-.46,.88,.6),opacity .1s;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-indeterminate .rc-tree-select-tree-checkbox-inner:after {
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: rgb(3, 179, 101) !important;
|
||||||
|
border: 0;
|
||||||
|
transform: translate(-50%,-50%) scale(1);
|
||||||
|
opacity: 1;
|
||||||
|
content: " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox:hover:after, .rc-tree-select-tree-checkbox-wrapper:hover .rc-tree-select-tree-checkbox:after {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox {
|
||||||
|
top: initial;
|
||||||
|
margin: 4px 8px 0 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-checkbox {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
color: #000000d9;
|
||||||
|
font-size: 14px;
|
||||||
|
font-variant: tabular-nums;
|
||||||
|
line-height: 1.5715;
|
||||||
|
list-style: none;
|
||||||
|
font-feature-settings: "tnum";
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-wrapper:hover .rc-tree-select-tree-checkbox-inner, .rc-tree-select-tree-checkbox:hover .rc-tree-select-tree-checkbox-inner, .rc-tree-select-tree-checkbox-input:focus+.rc-tree-select-tree-checkbox-inner {
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-checkbox-checked .rc-tree-select-tree-checkbox-inner {
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree-checkbox-inner {
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
direction: ltr;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #d9d9d9;
|
||||||
|
border-radius: 0px;
|
||||||
|
border-collapse: separate;
|
||||||
|
transition: all .3s;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree.select-tree-checkbox-checked {
|
||||||
|
.rc-tree-select-tree-checkbox-inner {
|
||||||
|
border-color: rgb(3, 179, 101) !important;
|
||||||
|
background: rgb(3, 179, 101) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.single-tree-select-dropdown
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle {
|
||||||
|
display: inline-block;
|
||||||
|
width: 0px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
vertical-align: -0.125em;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-attachment: scroll;
|
||||||
|
border: 0 none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-icon__customize,
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-checkbox.rc-tree-select-tree-icon__customize,
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-iconEle.rc-tree-select-tree-icon__customize {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-icon_loading {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-switcher-noop {
|
||||||
|
cursor: auto;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-switcher_open {
|
||||||
|
background-position: -93px -56px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
span.rc-tree-select-tree-switcher.rc-tree-select-tree-switcher_close {
|
||||||
|
background-position: -75px -56px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree:not(.rc-tree-select-tree-show-line)
|
||||||
|
.rc-tree-select-tree-treenode
|
||||||
|
.rc-tree-select-tree-switcher-noop {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree.rc-tree-select-tree-show-line
|
||||||
|
.rc-tree-select-tree-treenode:not(:last-child)
|
||||||
|
> ul {
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree.rc-tree-select-tree-show-line
|
||||||
|
.rc-tree-select-tree-treenode:not(:last-child)
|
||||||
|
> .rc-tree-select-tree-switcher-noop {
|
||||||
|
background-position: -56px -18px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree.rc-tree-select-tree-show-line
|
||||||
|
.rc-tree-select-tree-treenode:last-child
|
||||||
|
> .rc-tree-select-tree-switcher-noop {
|
||||||
|
background-position: -56px -36px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-child-tree {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-child-tree-open {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-treenode-disabled
|
||||||
|
> span:not(.rc-tree-select-tree-switcher),
|
||||||
|
.rc-tree-select-tree-treenode-disabled > a,
|
||||||
|
.rc-tree-select-tree-treenode-disabled > a span {
|
||||||
|
color: #767676;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-treenode-active {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-treenode:hover {
|
||||||
|
background: rgb(233, 250, 243);
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-node-selected {
|
||||||
|
background-color: none;
|
||||||
|
box-shadow: 0 0 0 0 #ffb951;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__open {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background-position: -110px -16px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__close {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background-position: -110px 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__docu {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
background-position: -110px -32px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-icon__customize {
|
||||||
|
margin-right: 2px;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-title {
|
||||||
|
display: inline-block;
|
||||||
|
margin-left: 10px;
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-indent {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: bottom;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
.rc-tree-select-tree-indent-unit {
|
||||||
|
width: 25px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const TreeSelectContainer = styled.div<{ compactMode: boolean }>`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: ${(props) => (props.compactMode ? "row" : "column")};
|
||||||
|
align-items: ${(props) => (props.compactMode ? "center" : "left")};
|
||||||
|
|
||||||
|
label.tree-select-label {
|
||||||
|
margin-bottom: ${(props) => (props.compactMode ? "0px" : "5px")};
|
||||||
|
margin-right: ${(props) => (props.compactMode ? "10px" : "0px")};
|
||||||
|
}
|
||||||
|
.rc-tree-select {
|
||||||
|
display: inline-block;
|
||||||
|
font-size: 12px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
cursor: pointer;
|
||||||
|
flex: 1 1;
|
||||||
|
.rc-tree-select-selection-placeholder {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 11px;
|
||||||
|
left: 11px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
transition: all 0.3s;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #bfbfbf;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
pointer-events: none;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search-input {
|
||||||
|
appearance: none;
|
||||||
|
&::-webkit-search-cancel-button {
|
||||||
|
display: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-overflow-item-suffix {
|
||||||
|
position: relative !important;
|
||||||
|
left: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
input {
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow.rc-tree-select-loading {
|
||||||
|
.rc-tree-select-arrow-icon {
|
||||||
|
&::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: 2px solid #999;
|
||||||
|
border-top-color: transparent;
|
||||||
|
border-bottom-color: transparent;
|
||||||
|
transform: none;
|
||||||
|
margin-top: 4px;
|
||||||
|
animation: rcSelectLoadingIcon 0.5s infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-single .rc-tree-select-selector {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 1px;
|
||||||
|
padding-right: 20px;
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid rgb(231, 231, 231);
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 100%;
|
||||||
|
transition: border-color 0.15s ease-in-out 0s,
|
||||||
|
box-shadow 0.15s ease-in-out 0s;
|
||||||
|
background-color: white;
|
||||||
|
height: 100%;
|
||||||
|
.rc-tree-select-selection-search {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
input {
|
||||||
|
width: 100%;
|
||||||
|
appearance: none;
|
||||||
|
&::-webkit-search-cancel-button {
|
||||||
|
display: none;
|
||||||
|
appearance: none;
|
||||||
|
}
|
||||||
|
font-family: system-ui;
|
||||||
|
|
||||||
|
height: 100%;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-item {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
right: 11px;
|
||||||
|
left: 11px;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
transition: all 0.3s;
|
||||||
|
flex: 1;
|
||||||
|
overflow: hidden;
|
||||||
|
color: #231f20;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
pointer-events: none;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-multiple {
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
padding-right: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding: 1px;
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid rgb(231, 231, 231);
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 100%;
|
||||||
|
transition: border-color 0.15s ease-in-out 0s,
|
||||||
|
box-shadow 0.15s ease-in-out 0s;
|
||||||
|
background-color: white;
|
||||||
|
.rc-tree-select-selection-item {
|
||||||
|
background: none;
|
||||||
|
border: 1px solid rgb(208, 215, 221);
|
||||||
|
border-radius: 2px;
|
||||||
|
margin: 3px 2px;
|
||||||
|
max-width: 273.926px;
|
||||||
|
height: 24px;
|
||||||
|
color: #182026;
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
display: inline-flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: none;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
min-height: 20px;
|
||||||
|
min-width: 20px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-item-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-overflow {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
width: 100%;
|
||||||
|
align-content: center;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-overflow-item {
|
||||||
|
flex: none;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search {
|
||||||
|
position: relative;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 2px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search-input {
|
||||||
|
padding: 1px;
|
||||||
|
font-family: system-ui;
|
||||||
|
width: 5px;
|
||||||
|
margin: 0px;
|
||||||
|
display: flex;
|
||||||
|
height: 26px;
|
||||||
|
flex: 1 1 0%;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-search-mirror {
|
||||||
|
padding: 1px;
|
||||||
|
font-family: system-ui;
|
||||||
|
width: 5px;
|
||||||
|
margin: 0px;
|
||||||
|
display: flex;
|
||||||
|
height: 26px;
|
||||||
|
flex: 1 1 0%;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
white-space: nowrap;
|
||||||
|
position: none;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-selection-item-content {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 1;
|
||||||
|
margin-right: 4px;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
word-wrap: normal;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 16px;
|
||||||
|
}
|
||||||
|
.rc-tree-select-allow-clear {
|
||||||
|
.rc-tree-select-clear {
|
||||||
|
position: absolute;
|
||||||
|
right: 20px;
|
||||||
|
right: 25px;
|
||||||
|
top: -1px;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
z-index: -1;
|
||||||
|
.rc-tree-select-clear-icon {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-allow-clear.rc-tree-select-focused {
|
||||||
|
.rc-tree-select-clear {
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow.rc-tree-select-multiple {
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
padding-right: 20px;
|
||||||
|
box-shadow: none;
|
||||||
|
border: 1px solid rgb(231, 231, 231);
|
||||||
|
border-radius: 0px;
|
||||||
|
height: inherit;
|
||||||
|
width: 100%;
|
||||||
|
transition: border-color 0.15s ease-in-out 0s,
|
||||||
|
box-shadow 0.15s ease-in-out 0s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow {
|
||||||
|
.rc-tree-select-arrow {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
right: 5px;
|
||||||
|
top: 0;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.rc-tree-select-arrow-icon {
|
||||||
|
&::after {
|
||||||
|
content: "";
|
||||||
|
border: 5px solid transparent;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
display: inline-block;
|
||||||
|
border-top-color: #999;
|
||||||
|
transform: translateY(5px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.rc-tree-select-show-arrow.rc-tree-select-focused {
|
||||||
|
.rc-tree-select-selector {
|
||||||
|
border: 1px solid rgb(128, 189, 255);
|
||||||
|
outline: 0px;
|
||||||
|
box-shadow: rgba(0, 123, 255, 0.25) 0px 0px 0px 0.1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const StyledCheckbox = styled(Checkbox)`
|
||||||
|
&&.${Classes.CHECKBOX}.${Classes.CONTROL} {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const inputIcon = (): JSX.Element => (
|
||||||
|
<svg data-icon="chevron-down" height="16" viewBox="0 0 16 16" width="16">
|
||||||
|
<desc>chevron-down</desc>
|
||||||
|
<path
|
||||||
|
d="M12 5c-.28 0-.53.11-.71.29L8 8.59l-3.29-3.3a1.003 1.003 0 00-1.42 1.42l4 4c.18.18.43.29.71.29s.53-.11.71-.29l4-4A1.003 1.003 0 0012 5z"
|
||||||
|
fillRule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
import React, {
|
||||||
|
ReactNode,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from "react";
|
||||||
|
import TreeSelect, { TreeSelectProps as SelectProps } from "rc-tree-select";
|
||||||
|
import {
|
||||||
|
TreeSelectContainer,
|
||||||
|
DropdownStyles,
|
||||||
|
inputIcon,
|
||||||
|
StyledLabel,
|
||||||
|
TextLabelWrapper,
|
||||||
|
} from "./index.styled";
|
||||||
|
import "rc-tree-select/assets/index.less";
|
||||||
|
import { DefaultValueType } from "rc-tree-select/lib/interface";
|
||||||
|
import { TreeNodeProps } from "rc-tree-select/lib/TreeNode";
|
||||||
|
import {
|
||||||
|
CANVAS_CLASSNAME,
|
||||||
|
MODAL_PORTAL_CLASSNAME,
|
||||||
|
TextSize,
|
||||||
|
} from "constants/WidgetConstants";
|
||||||
|
import { Classes } from "@blueprintjs/core";
|
||||||
|
|
||||||
|
export interface TreeSelectProps
|
||||||
|
extends Required<
|
||||||
|
Pick<
|
||||||
|
SelectProps,
|
||||||
|
| "disabled"
|
||||||
|
| "options"
|
||||||
|
| "placeholder"
|
||||||
|
| "loading"
|
||||||
|
| "dropdownStyle"
|
||||||
|
| "allowClear"
|
||||||
|
>
|
||||||
|
> {
|
||||||
|
value?: DefaultValueType;
|
||||||
|
onChange: (value?: DefaultValueType, labelList?: ReactNode[]) => void;
|
||||||
|
expandAll: boolean;
|
||||||
|
labelText?: string;
|
||||||
|
labelTextColor?: string;
|
||||||
|
labelTextSize?: TextSize;
|
||||||
|
labelStyle?: string;
|
||||||
|
compactMode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSvg = (style = {}) => (
|
||||||
|
<i
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
backgroundColor: "transparent",
|
||||||
|
display: "inline-flex",
|
||||||
|
width: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
fill="none"
|
||||||
|
height="10"
|
||||||
|
style={{ verticalAlign: "-.125em", ...style }}
|
||||||
|
viewBox="0 0 10 10"
|
||||||
|
width="10"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
clipRule="evenodd"
|
||||||
|
d="M2.5 9L7.5 5L2.5 1L2.5 9Z"
|
||||||
|
fill="#090707"
|
||||||
|
ill-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</i>
|
||||||
|
);
|
||||||
|
|
||||||
|
const switcherIcon = (treeNode: TreeNodeProps) => {
|
||||||
|
if (treeNode.isLeaf) {
|
||||||
|
return (
|
||||||
|
<i
|
||||||
|
style={{
|
||||||
|
cursor: "pointer",
|
||||||
|
backgroundColor: "white",
|
||||||
|
display: "inline-flex",
|
||||||
|
width: "10px",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return getSvg({ transform: `rotate(${treeNode.expanded ? 90 : 0}deg)` });
|
||||||
|
};
|
||||||
|
|
||||||
|
function SingleSelectTreeComponent({
|
||||||
|
allowClear,
|
||||||
|
compactMode,
|
||||||
|
disabled,
|
||||||
|
dropdownStyle,
|
||||||
|
expandAll,
|
||||||
|
labelStyle,
|
||||||
|
labelText,
|
||||||
|
labelTextColor,
|
||||||
|
labelTextSize,
|
||||||
|
loading,
|
||||||
|
onChange,
|
||||||
|
options,
|
||||||
|
placeholder,
|
||||||
|
value,
|
||||||
|
}: TreeSelectProps): JSX.Element {
|
||||||
|
const [key, setKey] = useState(Math.random());
|
||||||
|
const _menu = useRef<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
// treeDefaultExpandAll is uncontrolled after first render,
|
||||||
|
// using this to force render to respond to changes in expandAll
|
||||||
|
useEffect(() => {
|
||||||
|
setKey(Math.random());
|
||||||
|
}, [expandAll]);
|
||||||
|
|
||||||
|
const getDropdownPosition = useCallback(() => {
|
||||||
|
const node = _menu.current;
|
||||||
|
if (Boolean(node?.closest(`.${MODAL_PORTAL_CLASSNAME}`))) {
|
||||||
|
return document.querySelector(
|
||||||
|
`.${MODAL_PORTAL_CLASSNAME}`,
|
||||||
|
) as HTMLElement;
|
||||||
|
}
|
||||||
|
return document.querySelector(`.${CANVAS_CLASSNAME}`) as HTMLElement;
|
||||||
|
}, []);
|
||||||
|
const onClear = useCallback(() => onChange([], []), []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TreeSelectContainer
|
||||||
|
compactMode={compactMode}
|
||||||
|
ref={_menu as React.RefObject<HTMLDivElement>}
|
||||||
|
>
|
||||||
|
<DropdownStyles />
|
||||||
|
{labelText && (
|
||||||
|
<TextLabelWrapper compactMode={compactMode}>
|
||||||
|
<StyledLabel
|
||||||
|
$compactMode={compactMode}
|
||||||
|
$labelStyle={labelStyle}
|
||||||
|
$labelText={labelText}
|
||||||
|
$labelTextColor={labelTextColor}
|
||||||
|
$labelTextSize={labelTextSize}
|
||||||
|
className={`tree-select-label ${
|
||||||
|
loading ? Classes.SKELETON : Classes.TEXT_OVERFLOW_ELLIPSIS
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{labelText}
|
||||||
|
</StyledLabel>
|
||||||
|
</TextLabelWrapper>
|
||||||
|
)}
|
||||||
|
<TreeSelect
|
||||||
|
allowClear={allowClear}
|
||||||
|
animation="slide-up"
|
||||||
|
choiceTransitionName="rc-tree-select-selection__choice-zoom"
|
||||||
|
className="rc-tree-select"
|
||||||
|
disabled={disabled}
|
||||||
|
dropdownClassName="tree-select-dropdown single-tree-select-dropdown"
|
||||||
|
dropdownStyle={dropdownStyle}
|
||||||
|
getPopupContainer={getDropdownPosition}
|
||||||
|
inputIcon={inputIcon}
|
||||||
|
key={key}
|
||||||
|
loading={loading}
|
||||||
|
maxTagCount={"responsive"}
|
||||||
|
maxTagPlaceholder={(e) => `+${e.length} more`}
|
||||||
|
notFoundContent="No item Found"
|
||||||
|
onChange={onChange}
|
||||||
|
onClear={onClear}
|
||||||
|
placeholder={placeholder}
|
||||||
|
showArrow
|
||||||
|
showSearch
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
switcherIcon={switcherIcon}
|
||||||
|
transitionName="rc-tree-select-dropdown-slide-up"
|
||||||
|
treeData={options}
|
||||||
|
treeDefaultExpandAll={expandAll}
|
||||||
|
treeIcon
|
||||||
|
treeNodeFilterProp="label"
|
||||||
|
value={value}
|
||||||
|
/>
|
||||||
|
</TreeSelectContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingleSelectTreeComponent;
|
||||||
1
app/client/src/widgets/SingleSelectTreeWidget/icon.svg
Normal file
1
app/client/src/widgets/SingleSelectTreeWidget/icon.svg
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.75" y="0.75" width="18.5" height="6.5" stroke="#EAEAEA" stroke-width="1.5"/><path d="M7.99985 10.05L14.9998 10.05V11.55L7.99985 11.55L7.99985 10.05Z" fill="#EAEAEA"/><path d="M7.99985 14.75H13.9998V16.25L7.99985 16.25L7.99985 14.75Z" fill="#EAEAEA"/><path d="M5.99985 10.5L2.99985 10.5L4.49985 12L5.99985 10.5Z" fill="#EAEAEA"/><path d="M6 15L3 15L4.5 16.5L6 15Z" fill="#EAEAEA"/><path fill-rule="evenodd" clip-rule="evenodd" d="M0 6.5V20H18V6.5H0ZM1.5 18.5V8H16.5V18.5H1.5Z" fill="#EAEAEA"/><path d="M3 3.19995H17V4.69995H3V3.19995Z" fill="#EAEAEA"/></svg>
|
||||||
|
After Width: | Height: | Size: 664 B |
50
app/client/src/widgets/SingleSelectTreeWidget/index.ts
Normal file
50
app/client/src/widgets/SingleSelectTreeWidget/index.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
import Widget from "./widget";
|
||||||
|
import IconSVG from "./icon.svg";
|
||||||
|
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
|
||||||
|
|
||||||
|
export const CONFIG = {
|
||||||
|
type: Widget.getWidgetType(),
|
||||||
|
name: "Single Select Tree",
|
||||||
|
iconSVG: IconSVG,
|
||||||
|
needsMeta: true,
|
||||||
|
defaults: {
|
||||||
|
rows: 1.7 * GRID_DENSITY_MIGRATION_V1,
|
||||||
|
columns: 4 * GRID_DENSITY_MIGRATION_V1,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Blue",
|
||||||
|
value: "BLUE",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
label: "Dark Blue",
|
||||||
|
value: "DARK BLUE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Light Blue",
|
||||||
|
value: "LIGHT BLUE",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ label: "Green", value: "GREEN" },
|
||||||
|
{ label: "Red", value: "RED" },
|
||||||
|
],
|
||||||
|
widgetName: "SingleSelectTree",
|
||||||
|
defaultOptionValue: "BLUE",
|
||||||
|
version: 1,
|
||||||
|
isVisible: true,
|
||||||
|
isRequired: false,
|
||||||
|
isDisabled: false,
|
||||||
|
allowClear: false,
|
||||||
|
expandAll: false,
|
||||||
|
placeholderText: "select option",
|
||||||
|
labelText: "Label",
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
derived: Widget.getDerivedPropertiesMap(),
|
||||||
|
default: Widget.getDefaultPropertiesMap(),
|
||||||
|
meta: Widget.getMetaPropertiesMap(),
|
||||||
|
config: Widget.getPropertyPaneConfig(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Widget;
|
||||||
425
app/client/src/widgets/SingleSelectTreeWidget/widget/index.tsx
Normal file
425
app/client/src/widgets/SingleSelectTreeWidget/widget/index.tsx
Normal file
|
|
@ -0,0 +1,425 @@
|
||||||
|
import React, { ReactNode } from "react";
|
||||||
|
import BaseWidget, { WidgetProps, WidgetState } from "widgets/BaseWidget";
|
||||||
|
import { TextSize, WidgetType } from "constants/WidgetConstants";
|
||||||
|
import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
||||||
|
import { isArray, findIndex } from "lodash";
|
||||||
|
import {
|
||||||
|
ValidationResponse,
|
||||||
|
ValidationTypes,
|
||||||
|
} from "constants/WidgetValidation";
|
||||||
|
import { EvaluationSubstitutionType } from "entities/DataTree/dataTreeFactory";
|
||||||
|
import { DefaultValueType } from "rc-select/lib/interface/generator";
|
||||||
|
import { Layers } from "constants/Layers";
|
||||||
|
import { isString } from "../../../utils/helpers";
|
||||||
|
import { AutocompleteDataType } from "utils/autocomplete/TernServer";
|
||||||
|
import { GRID_DENSITY_MIGRATION_V1 } from "widgets/constants";
|
||||||
|
import SingleSelectTreeComponent from "../component";
|
||||||
|
|
||||||
|
function defaultOptionValueValidation(value: unknown): ValidationResponse {
|
||||||
|
if (typeof value === "string") return { isValid: true, parsed: value.trim() };
|
||||||
|
if (value === undefined || value === null)
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
parsed: "",
|
||||||
|
message: "This value does not evaluate to type: string",
|
||||||
|
};
|
||||||
|
return { isValid: true, parsed: value };
|
||||||
|
}
|
||||||
|
class SingleSelectTreeWidget extends BaseWidget<
|
||||||
|
SingleSelectTreeWidgetProps,
|
||||||
|
WidgetState
|
||||||
|
> {
|
||||||
|
static getPropertyPaneConfig() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
sectionName: "General",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
helpText:
|
||||||
|
"Allows users to select multiple options. Values must be unique",
|
||||||
|
propertyName: "options",
|
||||||
|
label: "Options",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter option value",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
isJSConvertible: false,
|
||||||
|
validation: {
|
||||||
|
type: ValidationTypes.NESTED_OBJECT_ARRAY,
|
||||||
|
params: {
|
||||||
|
unique: ["value"],
|
||||||
|
default: [],
|
||||||
|
children: {
|
||||||
|
type: ValidationTypes.OBJECT,
|
||||||
|
params: {
|
||||||
|
allowedKeys: [
|
||||||
|
{
|
||||||
|
name: "label",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "children",
|
||||||
|
type: ValidationTypes.ARRAY,
|
||||||
|
required: false,
|
||||||
|
params: {
|
||||||
|
children: {
|
||||||
|
type: ValidationTypes.OBJECT,
|
||||||
|
params: {
|
||||||
|
allowedKeys: [
|
||||||
|
{
|
||||||
|
name: "label",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "value",
|
||||||
|
type: ValidationTypes.TEXT,
|
||||||
|
params: {
|
||||||
|
default: "",
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
evaluationSubstitutionType:
|
||||||
|
EvaluationSubstitutionType.SMART_SUBSTITUTE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Selects the option with value by default",
|
||||||
|
propertyName: "defaultOptionValue",
|
||||||
|
label: "Default Value",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter option value",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: {
|
||||||
|
type: ValidationTypes.FUNCTION,
|
||||||
|
params: {
|
||||||
|
fn: defaultOptionValueValidation,
|
||||||
|
expected: {
|
||||||
|
type: "value",
|
||||||
|
example: `value1`,
|
||||||
|
autocompleteDataType: AutocompleteDataType.STRING,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Label Text",
|
||||||
|
propertyName: "labelText",
|
||||||
|
label: "Label Text",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter Label text",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Input Place Holder",
|
||||||
|
propertyName: "placeholderText",
|
||||||
|
label: "Placeholder",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
placeholderText: "Enter placeholder text",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
helpText: "Controls the visibility of the widget",
|
||||||
|
propertyName: "isVisible",
|
||||||
|
label: "Visible",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "isDisabled",
|
||||||
|
label: "Disabled",
|
||||||
|
helpText: "Disables input to this widget",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "isRequired",
|
||||||
|
label: "Required",
|
||||||
|
helpText: "Makes input to the widget mandatory",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "allowClear",
|
||||||
|
label: "Clear all Selections",
|
||||||
|
helpText: "Enables Icon to clear all Selections",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "expandAll",
|
||||||
|
label: "Expand all by default",
|
||||||
|
helpText: "Expand All nested options",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.BOOLEAN },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sectionName: "Styles",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
propertyName: "labelTextColor",
|
||||||
|
label: "Label Text Color",
|
||||||
|
controlType: "COLOR_PICKER",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "labelTextSize",
|
||||||
|
label: "Label Text Size",
|
||||||
|
controlType: "DROP_DOWN",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
label: "Heading 1",
|
||||||
|
value: "HEADING1",
|
||||||
|
subText: "24px",
|
||||||
|
icon: "HEADING_ONE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Heading 2",
|
||||||
|
value: "HEADING2",
|
||||||
|
subText: "18px",
|
||||||
|
icon: "HEADING_TWO",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Heading 3",
|
||||||
|
value: "HEADING3",
|
||||||
|
subText: "16px",
|
||||||
|
icon: "HEADING_THREE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Paragraph",
|
||||||
|
value: "PARAGRAPH",
|
||||||
|
subText: "14px",
|
||||||
|
icon: "PARAGRAPH",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Paragraph 2",
|
||||||
|
value: "PARAGRAPH2",
|
||||||
|
subText: "12px",
|
||||||
|
icon: "PARAGRAPH_TWO",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "labelStyle",
|
||||||
|
label: "Label Font Style",
|
||||||
|
controlType: "BUTTON_TABS",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
icon: "BOLD_FONT",
|
||||||
|
value: "BOLD",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: "ITALICS_FONT",
|
||||||
|
value: "ITALIC",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: { type: ValidationTypes.TEXT },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sectionName: "Actions",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
helpText: "Triggers an action when a user selects an option",
|
||||||
|
propertyName: "onOptionChange",
|
||||||
|
label: "onOptionChange",
|
||||||
|
controlType: "ACTION_SELECTOR",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDerivedPropertiesMap() {
|
||||||
|
return {
|
||||||
|
selectedOptionLabel: `{{ this.selectedLabel[0] }}`,
|
||||||
|
selectedOptionValue:
|
||||||
|
'{{ JSON.stringify(this.options).match(new RegExp(`"value":"${this.selectedOption}"`), "g") ? this.selectedOption : undefined }}',
|
||||||
|
isValid: `{{this.isRequired ? !!this.selectedOptionValue?.length : true}}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getDefaultPropertiesMap(): Record<string, string> {
|
||||||
|
return {
|
||||||
|
selectedOption: "defaultOptionValue",
|
||||||
|
selectedLabel: "defaultOptionValue",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static getMetaPropertiesMap(): Record<string, any> {
|
||||||
|
return {
|
||||||
|
selectedOption: undefined,
|
||||||
|
selectedOptionValueArr: undefined,
|
||||||
|
selectedLabel: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getPageView() {
|
||||||
|
const options =
|
||||||
|
isArray(this.props.options) &&
|
||||||
|
!this.props.__evaluation__?.errors.options.length
|
||||||
|
? this.props.options
|
||||||
|
: [];
|
||||||
|
const values: string | undefined = isString(this.props.selectedOption)
|
||||||
|
? this.props.selectedOption
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const filteredValue = this.filterValues(values);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SingleSelectTreeComponent
|
||||||
|
allowClear={this.props.allowClear}
|
||||||
|
compactMode={
|
||||||
|
!(
|
||||||
|
(this.props.bottomRow - this.props.topRow) /
|
||||||
|
GRID_DENSITY_MIGRATION_V1 >
|
||||||
|
1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
disabled={this.props.isDisabled ?? false}
|
||||||
|
dropdownStyle={{
|
||||||
|
zIndex: Layers.dropdownModalWidget,
|
||||||
|
}}
|
||||||
|
expandAll={this.props.expandAll}
|
||||||
|
labelStyle={this.props.labelStyle}
|
||||||
|
labelText={this.props.labelText}
|
||||||
|
labelTextColor={this.props.labelTextColor}
|
||||||
|
labelTextSize={this.props.labelTextSize}
|
||||||
|
loading={this.props.isLoading}
|
||||||
|
onChange={this.onOptionChange}
|
||||||
|
options={options}
|
||||||
|
placeholder={this.props.placeholderText as string}
|
||||||
|
value={filteredValue}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
onOptionChange = (value?: DefaultValueType, labelList?: ReactNode[]) => {
|
||||||
|
this.props.updateWidgetMetaProperty("selectedLabel", labelList, {
|
||||||
|
triggerPropertyName: "onOptionChange",
|
||||||
|
dynamicString: this.props.onOptionChange,
|
||||||
|
event: {
|
||||||
|
type: EventType.ON_OPTION_CHANGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.updateWidgetMetaProperty("selectedOption", value, {
|
||||||
|
triggerPropertyName: "onOptionChange",
|
||||||
|
dynamicString: this.props.onOptionChange,
|
||||||
|
event: {
|
||||||
|
type: EventType.ON_OPTION_CHANGE,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
flat(array: DropdownOption[]) {
|
||||||
|
let result: { value: string }[] = [];
|
||||||
|
array.forEach((a) => {
|
||||||
|
result.push({ value: a.value });
|
||||||
|
if (Array.isArray(a.children)) {
|
||||||
|
result = result.concat(this.flat(a.children));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterValues(values: string | undefined) {
|
||||||
|
const options = this.props.options ? this.flat(this.props.options) : [];
|
||||||
|
|
||||||
|
if (isString(values)) {
|
||||||
|
const index = findIndex(options, { value: values as string });
|
||||||
|
return index > -1 ? values : undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getWidgetType(): WidgetType {
|
||||||
|
return "SINGLE_SELECT_TREE_WIDGET";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropdownOption {
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
children?: DropdownOption[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SingleSelectTreeWidgetProps extends WidgetProps {
|
||||||
|
placeholderText?: string;
|
||||||
|
selectedIndex?: number;
|
||||||
|
options?: DropdownOption[];
|
||||||
|
onOptionChange: string;
|
||||||
|
defaultOptionValue: string;
|
||||||
|
isRequired: boolean;
|
||||||
|
isLoading: boolean;
|
||||||
|
allowClear: boolean;
|
||||||
|
labelText?: string;
|
||||||
|
selectedLabel: string[];
|
||||||
|
selectedOption: string;
|
||||||
|
selectedOptionValue: string;
|
||||||
|
selectedOptionLabel: string;
|
||||||
|
expandAll: boolean;
|
||||||
|
labelTextColor?: string;
|
||||||
|
labelTextSize?: TextSize;
|
||||||
|
labelStyle?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SingleSelectTreeWidget;
|
||||||
|
|
@ -22,6 +22,16 @@ import evaluate from "./evaluate";
|
||||||
import getIsSafeURL from "utils/validation/getIsSafeURL";
|
import getIsSafeURL from "utils/validation/getIsSafeURL";
|
||||||
export const UNDEFINED_VALIDATION = "UNDEFINED_VALIDATION";
|
export const UNDEFINED_VALIDATION = "UNDEFINED_VALIDATION";
|
||||||
|
|
||||||
|
const flat = (array: Record<string, any>[], uniqueParam: string) => {
|
||||||
|
let result: { value: string }[] = [];
|
||||||
|
array.forEach((a) => {
|
||||||
|
result.push({ value: a[uniqueParam] });
|
||||||
|
if (Array.isArray(a.children)) {
|
||||||
|
result = result.concat(flat(a.children, uniqueParam));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
};
|
||||||
function validatePlainObject(
|
function validatePlainObject(
|
||||||
config: ValidationConfig,
|
config: ValidationConfig,
|
||||||
value: Record<string, unknown>,
|
value: Record<string, unknown>,
|
||||||
|
|
@ -242,6 +252,7 @@ export function getExpectedType(config?: ValidationConfig): string | undefined {
|
||||||
}
|
}
|
||||||
return type;
|
return type;
|
||||||
case ValidationTypes.ARRAY:
|
case ValidationTypes.ARRAY:
|
||||||
|
case ValidationTypes.NESTED_OBJECT_ARRAY:
|
||||||
if (config.params?.allowedValues) {
|
if (config.params?.allowedValues) {
|
||||||
const allowed = config.params?.allowedValues.join("' | '");
|
const allowed = config.params?.allowedValues.join("' | '");
|
||||||
return `Array<'${allowed}'>`;
|
return `Array<'${allowed}'>`;
|
||||||
|
|
@ -626,6 +637,42 @@ export const VALIDATORS: Record<ValidationTypes, Validator> = {
|
||||||
}
|
}
|
||||||
return invalidResponse;
|
return invalidResponse;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[ValidationTypes.NESTED_OBJECT_ARRAY]: (
|
||||||
|
config: ValidationConfig,
|
||||||
|
value: unknown,
|
||||||
|
props: Record<string, unknown>,
|
||||||
|
): ValidationResponse => {
|
||||||
|
let response: ValidationResponse = {
|
||||||
|
isValid: false,
|
||||||
|
parsed: config.params?.default || [],
|
||||||
|
message: `${WIDGET_TYPE_VALIDATION_ERROR} ${getExpectedType(config)}`,
|
||||||
|
};
|
||||||
|
response = VALIDATORS.ARRAY(config, value, props);
|
||||||
|
|
||||||
|
if (!response.isValid) {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
// Check if all values and children values are unique
|
||||||
|
if (config.params?.unique && response.parsed.length) {
|
||||||
|
if (isArray(config.params?.unique)) {
|
||||||
|
for (const param of config.params?.unique) {
|
||||||
|
const flattenedArray = flat(response.parsed, param);
|
||||||
|
const shouldBeUnique = flattenedArray.map((entry) =>
|
||||||
|
get(entry, param, ""),
|
||||||
|
);
|
||||||
|
if (uniq(shouldBeUnique).length !== flattenedArray.length) {
|
||||||
|
response = {
|
||||||
|
...response,
|
||||||
|
isValid: false,
|
||||||
|
message: `Array entry path:${param} must be unique. Duplicate values found`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
},
|
||||||
[ValidationTypes.DATE_ISO_STRING]: (
|
[ValidationTypes.DATE_ISO_STRING]: (
|
||||||
config: ValidationConfig,
|
config: ValidationConfig,
|
||||||
value: unknown,
|
value: unknown,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
// Import this named export into your test file:
|
// Import this named export into your test file:
|
||||||
export const mockExecute = jest.fn().mockImplementation((src, data) => {
|
export const mockExecute = jest.fn().mockImplementation((src, data) => {
|
||||||
let finalSource = "let ";
|
let finalSource = "let ";
|
||||||
Object.keys(data).forEach(key => {
|
Object.keys(data).forEach((key) => {
|
||||||
finalSource += ` ${key} = ${JSON.stringify(data[key])}, `;
|
finalSource += ` ${key} = ${JSON.stringify(data[key])}, `;
|
||||||
});
|
});
|
||||||
finalSource = finalSource.substring(0, finalSource.length - 2) + ";";
|
finalSource = finalSource.substring(0, finalSource.length - 2) + ";";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
export const ContainerFactory = Factory.Sync.makeFactory<WidgetProps>({
|
export const ContainerFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
backgroundColor: "#FFFFFF",
|
backgroundColor: "#FFFFFF",
|
||||||
widgetName: Factory.each((i) => `Container${(i+1)}` ),
|
widgetName: Factory.each((i) => `Container${i + 1}`),
|
||||||
type: "CONTAINER_WIDGET",
|
type: "CONTAINER_WIDGET",
|
||||||
containerStyle: "card",
|
containerStyle: "card",
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
|
|
|
||||||
|
|
@ -14,25 +14,27 @@ export const RadiogroupFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
defaultOptionValue: "1",
|
defaultOptionValue: "1",
|
||||||
parentColumnSpace: 34.6875,
|
parentColumnSpace: 34.6875,
|
||||||
leftColumn: 12,
|
leftColumn: 12,
|
||||||
dynamicTriggerPathList: [{
|
dynamicTriggerPathList: [
|
||||||
key: "onSelectionChange"
|
{
|
||||||
}],
|
key: "onSelectionChange",
|
||||||
|
},
|
||||||
|
],
|
||||||
onSelectionChange: "{{navigateTo()}}",
|
onSelectionChange: "{{navigateTo()}}",
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
id: "1",
|
id: "1",
|
||||||
label: "jarvis",
|
label: "jarvis",
|
||||||
value: "1"
|
value: "1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "2",
|
id: "2",
|
||||||
label: "marvel",
|
label: "marvel",
|
||||||
value: "2"
|
value: "2",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "iron",
|
label: "iron",
|
||||||
value: "4"
|
value: "4",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
dynamicBindingPathList: [],
|
dynamicBindingPathList: [],
|
||||||
widgetName: Factory.each((i) => `RadioGroup${i + 1}`),
|
widgetName: Factory.each((i) => `RadioGroup${i + 1}`),
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { generateReactKey } from "utils/generators";
|
||||||
import { WidgetProps } from "widgets/BaseWidget";
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
export const TextFactory = Factory.Sync.makeFactory<WidgetProps>({
|
export const TextFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
widgetName: Factory.each((i) => `Text${(i+1)}`),
|
widgetName: Factory.each((i) => `Text${i + 1}`),
|
||||||
rightColumn: 12,
|
rightColumn: 12,
|
||||||
onClick: "",
|
onClick: "",
|
||||||
isDefaultClickDisabled: true,
|
isDefaultClickDisabled: true,
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,10 @@ import React from "react";
|
||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { mockGetCanvasWidgetDsl, useMockDsl } from "./testCommon";
|
import { mockGetCanvasWidgetDsl, useMockDsl } from "./testCommon";
|
||||||
|
|
||||||
export const MockCanvas = () => {
|
export function MockCanvas() {
|
||||||
const dsl = useSelector(mockGetCanvasWidgetDsl);
|
const dsl = useSelector(mockGetCanvasWidgetDsl);
|
||||||
return <Canvas dsl={dsl}></Canvas>;
|
return <Canvas dsl={dsl} />;
|
||||||
};
|
}
|
||||||
export function UpdatedMainContainer({ dsl }: any) {
|
export function UpdatedMainContainer({ dsl }: any) {
|
||||||
useMockDsl(dsl);
|
useMockDsl(dsl);
|
||||||
return <MainContainer />;
|
return <MainContainer />;
|
||||||
|
|
|
||||||
|
|
@ -14789,7 +14789,7 @@ rc-resize-observer@^1.0.0:
|
||||||
rc-util "^5.0.0"
|
rc-util "^5.0.0"
|
||||||
resize-observer-polyfill "^1.5.1"
|
resize-observer-polyfill "^1.5.1"
|
||||||
|
|
||||||
rc-select@^12.1.10:
|
rc-select@^12.0.0, rc-select@^12.1.10:
|
||||||
version "12.1.13"
|
version "12.1.13"
|
||||||
resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-12.1.13.tgz#c33560ccb9339d30695b52458f55efc35af35273"
|
resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-12.1.13.tgz#c33560ccb9339d30695b52458f55efc35af35273"
|
||||||
integrity sha512-cPI+aesP6dgCAaey4t4upDbEukJe+XN0DK6oO/6flcCX5o28o7KNZD7JAiVtC/6fCwqwI/kSs7S/43dvHmBl+A==
|
integrity sha512-cPI+aesP6dgCAaey4t4upDbEukJe+XN0DK6oO/6flcCX5o28o7KNZD7JAiVtC/6fCwqwI/kSs7S/43dvHmBl+A==
|
||||||
|
|
@ -14802,6 +14802,28 @@ rc-select@^12.1.10:
|
||||||
rc-util "^5.9.8"
|
rc-util "^5.9.8"
|
||||||
rc-virtual-list "^3.2.0"
|
rc-virtual-list "^3.2.0"
|
||||||
|
|
||||||
|
rc-tree-select@^4.4.0-alpha.2:
|
||||||
|
version "4.4.0-alpha.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/rc-tree-select/-/rc-tree-select-4.4.0-alpha.2.tgz#b96019bd401084076bedac4e49ea50321709b273"
|
||||||
|
integrity sha512-8PdODhXpNK13z5u3P0uWb8+ghDtpkQ+ImhxgTXZxBj1KSSi0fB1Ey/mHFLP/R3r72vmwMRGkfkpbW2G6ZRtipw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.10.1"
|
||||||
|
classnames "2.x"
|
||||||
|
rc-select "^12.0.0"
|
||||||
|
rc-tree "^4.0.0"
|
||||||
|
rc-util "^5.0.5"
|
||||||
|
|
||||||
|
rc-tree@^4.0.0:
|
||||||
|
version "4.2.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/rc-tree/-/rc-tree-4.2.2.tgz#4429187cbbfbecbe989714a607e3de8b3ab7763f"
|
||||||
|
integrity sha512-V1hkJt092VrOVjNyfj5IYbZKRMHxWihZarvA5hPL/eqm7o2+0SNkeidFYm7LVVBrAKBpOpa0l8xt04uiqOd+6w==
|
||||||
|
dependencies:
|
||||||
|
"@babel/runtime" "^7.10.1"
|
||||||
|
classnames "2.x"
|
||||||
|
rc-motion "^2.0.1"
|
||||||
|
rc-util "^5.0.0"
|
||||||
|
rc-virtual-list "^3.0.1"
|
||||||
|
|
||||||
rc-trigger@^5.0.4:
|
rc-trigger@^5.0.4:
|
||||||
version "5.2.9"
|
version "5.2.9"
|
||||||
resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.2.9.tgz#795a787d2b038347dcde27b89a4a5cec8fc40f3e"
|
resolved "https://registry.yarnpkg.com/rc-trigger/-/rc-trigger-5.2.9.tgz#795a787d2b038347dcde27b89a4a5cec8fc40f3e"
|
||||||
|
|
@ -14813,7 +14835,7 @@ rc-trigger@^5.0.4:
|
||||||
rc-motion "^2.0.0"
|
rc-motion "^2.0.0"
|
||||||
rc-util "^5.5.0"
|
rc-util "^5.5.0"
|
||||||
|
|
||||||
rc-util@^5.0.0, rc-util@^5.0.7, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.5.0, rc-util@^5.5.1, rc-util@^5.9.8:
|
rc-util@^5.0.0, rc-util@^5.0.5, rc-util@^5.0.7, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.5.0, rc-util@^5.5.1, rc-util@^5.9.8:
|
||||||
version "5.13.2"
|
version "5.13.2"
|
||||||
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.13.2.tgz#a8a0bb77743351841ba8bed6393e03b8d2f685c8"
|
resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.13.2.tgz#a8a0bb77743351841ba8bed6393e03b8d2f685c8"
|
||||||
integrity sha512-eYc71XXGlp96RMzg01Mhq/T3BL6OOVTDSS0urFEuvpi+e7slhJRhaHGCKy2hqJm18m9ff7VoRoptplKu60dYog==
|
integrity sha512-eYc71XXGlp96RMzg01Mhq/T3BL6OOVTDSS0urFEuvpi+e7slhJRhaHGCKy2hqJm18m9ff7VoRoptplKu60dYog==
|
||||||
|
|
@ -14822,7 +14844,7 @@ rc-util@^5.0.0, rc-util@^5.0.7, rc-util@^5.2.1, rc-util@^5.3.0, rc-util@^5.5.0,
|
||||||
react-is "^16.12.0"
|
react-is "^16.12.0"
|
||||||
shallowequal "^1.1.0"
|
shallowequal "^1.1.0"
|
||||||
|
|
||||||
rc-virtual-list@^3.2.0:
|
rc-virtual-list@^3.0.1, rc-virtual-list@^3.2.0:
|
||||||
version "3.3.0"
|
version "3.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.3.0.tgz#2f95a6ddbbf63d78b28662b57f1e69f7472762fe"
|
resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.3.0.tgz#2f95a6ddbbf63d78b28662b57f1e69f7472762fe"
|
||||||
integrity sha512-lVXpGWC6yMdwV2SHo6kc63WlqjCnb3eO72V726KA2/wh9KA6wi/swcdR3zAowuA8hJxG/lRANmY5kpLZ+Pz3iQ==
|
integrity sha512-lVXpGWC6yMdwV2SHo6kc63WlqjCnb3eO72V726KA2/wh9KA6wi/swcdR3zAowuA8hJxG/lRANmY5kpLZ+Pz3iQ==
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user