diff --git a/app/client/cypress/fixtures/EmptyListWidget.json b/app/client/cypress/fixtures/EmptyListWidget.json new file mode 100644 index 00000000000..b60cf3fd24f --- /dev/null +++ b/app/client/cypress/fixtures/EmptyListWidget.json @@ -0,0 +1,170 @@ +{ + "dsl":{ + "widgetName":"MainContainer", + "backgroundColor":"none", + "rightColumn":1296, + "snapColumns":64, + "detachFromLayout":true, + "widgetId":"0", + "topRow":0, + "bottomRow":800, + "containerStyle":"none", + "snapRows":125, + "parentRowSpace":1, + "type":"CANVAS_WIDGET", + "canExtend":true, + "version":51, + "minHeight":810, + "parentColumnSpace":1, + "dynamicBindingPathList":[ + + ], + "leftColumn":0, + "children":[ + { + "isVisible":true, + "backgroundColor":"transparent", + "itemBackgroundColor":"#FFFFFF", + "animateLoading":true, + "gridType":"vertical", + "template":{ + + }, + "enhancements":true, + "gridGap":0, + "listData":[ + { + "id":"001", + "name":"Blue", + "img":"https://assets.appsmith.com/widgets/default.png" + }, + { + "id":"002", + "name":"Green", + "img":"https://assets.appsmith.com/widgets/default.png" + }, + { + "id":"003", + "name":"Red", + "img":"https://assets.appsmith.com/widgets/default.png" + } + ], + "widgetName":"List1", + "children":[ + { + "isVisible":true, + "widgetName":"Canvas6", + "version":1, + "detachFromLayout":true, + "type":"CANVAS_WIDGET", + "hideCard":true, + "displayName":"Canvas", + "key":"prgmua3liw", + "containerStyle":"none", + "canExtend":false, + "dropDisabled":true, + "openParentPropertyPane":true, + "noPad":true, + "children":[ + { + "isVisible":true, + "backgroundColor":"white", + "widgetName":"Container1", + "containerStyle":"card", + "borderColor":"transparent", + "borderWidth":"0", + "borderRadius":"0", + "boxShadow":"NONE", + "animateLoading":true, + "children":[ + { + "isVisible":true, + "widgetName":"Canvas7", + "version":1, + "detachFromLayout":true, + "type":"CANVAS_WIDGET", + "hideCard":true, + "displayName":"Canvas", + "key":"prgmua3liw", + "containerStyle":"none", + "canExtend":false, + "children":[ + + ], + "minHeight":null, + "widgetId":"wof8oynef3", + "renderMode":"CANVAS", + "isLoading":false, + "parentColumnSpace":1, + "parentRowSpace":1, + "leftColumn":0, + "rightColumn":null, + "topRow":0, + "bottomRow":20, + "parentId":"72hv75hszx" + } + ], + "version":1, + "type":"CONTAINER_WIDGET", + "hideCard":false, + "displayName":"Container", + "key":"5v3ghmpxex", + "iconSVG":"/static/media/icon.1977dca3.svg", + "isCanvas":true, + "dragDisabled":true, + "isDeletable":false, + "disallowCopy":true, + "disablePropertyPane":true, + "openParentPropertyPane":true, + "widgetId":"72hv75hszx", + "renderMode":"CANVAS", + "isLoading":false, + "leftColumn":0, + "rightColumn":64, + "topRow":0, + "bottomRow":62, + "parentId":"vnwk63rc14" + } + ], + "minHeight":400, + "widgetId":"vnwk63rc14", + "renderMode":"CANVAS", + "isLoading":false, + "parentColumnSpace":1, + "parentRowSpace":1, + "leftColumn":0, + "rightColumn":481.5, + "topRow":0, + "bottomRow":640, + "parentId":"1qyviq7phz" + } + ], + "type":"LIST_WIDGET", + "hideCard":false, + "displayName":"List", + "key":"twqaemvoat", + "iconSVG":"/static/media/icon.9925ee17.svg", + "isCanvas":true, + "widgetId":"1qyviq7phz", + "renderMode":"CANVAS", + "isLoading":false, + "parentColumnSpace":20.0625, + "parentRowSpace":10, + "leftColumn":3, + "rightColumn":50, + "topRow":3, + "bottomRow":72, + "parentId":"0", + "dynamicBindingPathList":[ + + ], + "privateWidgets":{ + + }, + "dynamicTriggerPathList":[ + + ] + } + ] + } +} \ No newline at end of file diff --git a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/List_spec.js b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/List_spec.js index 3d9548c8585..a1634ab7ca4 100644 --- a/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/List_spec.js +++ b/app/client/cypress/integration/Smoke_TestSuite/ClientSideTests/DisplayWidgets/List_spec.js @@ -1,19 +1,73 @@ -const dsl = require("../../../../fixtures/newFormDsl.json"); -const publishPage = require("../../../../locators/publishWidgetspage.json"); +const dsl = require("../../../../fixtures/EmptyListWidget.json"); +const explorer = require("../../../../locators/explorerlocators.json"); +const widgetsPage = require("../../../../locators/Widgets.json"); -describe("Button Widget Functionality", function() { +describe("List Widget Functionality", function() { before(() => { cy.addDsl(dsl); }); - beforeEach(() => { - cy.openPropertyPane("buttonwidget"); - }); + it("should validate that restricted widgets cannot be added to List", () => { + cy.get(explorer.addWidget).click(); + + const allowed = [ + "audiowidget", + "buttongroupwidget", + "buttonwidget", + "chartwidget", + "checkboxwidget", + "checkboxgroupwidget", + "circularprogresswidget", + "dividerwidget", + "iconbuttonwidget", + "iframewidget", + "imagewidget", + "inputwidgetv2", + "mapchartwidget", + "mapwidget", + "menubuttonwidget", + "progressbarwidget", + "statboxwidget", + "switchwidget", + "switchgroupwidget", + "textwidget", + "videowidget", + ]; + + const disallowed = [ + "containerwidget", + "tablewidget", + "radiogroupwidget", + "tabswidget", + "richtexteditorwidget", + "datepickerwidget2", + "formwidget", + "listwidget", + "filepickerwidgetv2", + "audiorecorderwidget", + "documentviewerwidget", + "multiselecttreewidget", + "singleselecttreewidget", + "camerawidget", + "selectwidget", + "multiselectwidgetv2", + "phoneinputwidget", + "currencyinputwidget", + ]; + + allowed.forEach((widget) => { + cy.dragAndDropToWidget(widget, "listwidget", { x: 50, y: 50 }); + cy.get(`.t--widget-${widget}`).should("exist"); + cy.get(widgetsPage.removeWidget).click({ force: true }); + cy.wait("@updateLayout"); + }); - it("Button-Color Validation", function() { - // Changing the color of the button from the property pane and verifying it. - cy.changeButtonColor("rgb(254, 184, 17)"); - cy.get(publishPage.backToEditor).click({ force: true }); + disallowed.forEach((widget) => { + cy.dragAndDropToWidget(widget, "listwidget", { x: 50, y: 50 }); + cy.validateToastMessage( + "This widget cannot be used inside the list widget.", + ); + }); }); afterEach(() => { diff --git a/app/client/src/utils/WidgetRegistry.tsx b/app/client/src/utils/WidgetRegistry.tsx index 270f46f7f6b..28d4adcf1fd 100644 --- a/app/client/src/utils/WidgetRegistry.tsx +++ b/app/client/src/utils/WidgetRegistry.tsx @@ -192,6 +192,11 @@ export const ALL_WIDGETS_AND_CONFIG = [ [InputWidgetV2, INPUT_WIDGET_V2_CONFIG], [PhoneInputWidget, PHONE_INPUT_WIDGET_V2_CONFIG], [CurrencyInputWidget, CURRENCY_INPUT_WIDGET_V2_CONFIG], + /* + * If a newly added widget works well inside the list widget, + * please add widget type in the List widget's allowed widget + * list, to make the new widget be droppable inside List widget. + */ ]; export const registerWidgets = () => { diff --git a/app/client/src/widgets/ListWidget/index.ts b/app/client/src/widgets/ListWidget/index.ts index d1bb2433637..ab545f71bcc 100644 --- a/app/client/src/widgets/ListWidget/index.ts +++ b/app/client/src/widgets/ListWidget/index.ts @@ -317,15 +317,38 @@ export const CONFIG = { const parent = { ...widgets[parentId] }; const logBlackList: { [key: string]: boolean } = {}; - const disallowedWidgets = [ - "TABLE_WIDGET", - "LIST_WIDGET", - "TABS_WIDGET", - "FORM_WIDGET", - "CONTAINER_WIDGET", + /* + * Only widgets that don't have derived or meta properties + * work well inside the current version of List widget. + * Widgets like Input, Select maintain the state on meta properties, + * which won't be available in List.selectedItem object. Hence we're + * restricting them from being placed inside the List widget. + */ + const allowedWidgets = [ + "AUDIO_WIDGET", + "BUTTON_GROUP_WIDGET", + "BUTTON_WIDGET", + "CHART_WIDGET", + "CHECKBOX_WIDGET", + "CHECKBOX_GROUP_WIDGET", + "CIRCULAR_PROGRESS_WIDGET", + "DIVIDER_WIDGET", + "ICON_BUTTON_WIDGET", + "IFRAME_WIDGET", + "IMAGE_WIDGET", + "INPUT_WIDGET_V2", + "MAP_CHART_WIDGET", + "MAP_WIDGET", + "MENU_BUTTON_WIDGET", + "PROGRESSBAR_WIDGET", + "STATBOX_WIDGET", + "SWITCH_WIDGET", + "SWITCH_GROUP_WIDGET", + "TEXT_WIDGET", + "VIDEO_WIDGET", ]; - if (indexOf(disallowedWidgets, widget.type) > -1) { + if (indexOf(allowedWidgets, widget.type) === -1) { const widget = widgets[widgetId]; if (widget.children && widget.children.length > 0) { widget.children.forEach((childId: string) => {