From 5d44d4f2cfdde04e63b170b1c568ecc00a4c989e Mon Sep 17 00:00:00 2001 From: balajisoundar Date: Tue, 16 Jan 2024 10:52:17 +0530 Subject: [PATCH] chore: misc updates to custom widget (#30114) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### PR fixes following issue(s) Fixes https://github.com/appsmithorg/appsmith/issues/29991 Fixes https://github.com/appsmithorg/appsmith/issues/30154 Fixes https://github.com/appsmithorg/appsmith/issues/30020 Fixes https://github.com/appsmithorg/appsmith/issues/30019 Fixes https://github.com/appsmithorg/appsmith/issues/30130 Fixes https://github.com/appsmithorg/appsmith/issues/30159 Fixes https://github.com/appsmithorg/appsmith/issues/30223 #### Media > A video or a GIF is preferred. when using Loom, don’t embed because it looks like it’s a GIF. instead, just link to the video > > #### Type of change > Please delete options that are not relevant. - Bug fix (non-breaking change which fixes an issue) - New feature (non-breaking change which adds functionality) - Breaking change (fix or feature that would cause existing functionality to not work as expected) - Chore (housekeeping or task changes that don't impact user perception) - This change requires a documentation update > > > ## Testing > #### How Has This Been Tested? > Please describe the tests that you ran to verify your changes. Also list any relevant details for your test configuration. > Delete anything that is not relevant - [ ] Manual - [ ] JUnit - [ ] Jest - [ ] Cypress > > #### Test Plan > Add Testsmith test cases links that relate to this PR > > #### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) > > > ## Checklist: #### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [ ] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [ ] Test plan covers all impacted features and [areas of interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-) - [ ] Test plan has been peer reviewed by project stakeholders and other QA members - [ ] Manually tested functionality on DP - [ ] We had an implementation alignment call with stakeholders post QA Round 2 - [ ] Cypress test cases have been added and approved by SDET/manual QA - [ ] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed ## Summary by CodeRabbit - **New Features** - Custom widgets now support analytics events, enhancing visibility into user interactions. - Template selection, layout controls, and reference triggers in the Custom Widget Builder are now integrated with analytics. - Added new style options for custom widgets, including `primaryColor`, `backgroundColor`, `borderRadius`, and `boxShadow`. - **Bug Fixes** - Corrected a typo in the constant title for better clarity. - Updated help text for the Container Widget to accurately describe the widget's border edge. - **Enhancements** - Improved user interface with additional styling for reference names in the Custom Widget Builder. - Enhanced debugger functionality with `useCallback` optimization and new analytics logging. - **Refactor** - Streamlined the property pane by introducing a new `LabelContainer` styled component. - Refined the handling of dynamic binding paths to ignore certain properties efficiently. - **Documentation** - Added a new constant for the default model documentation URL in the Custom Widget Builder. --- .../CustomWidgetEditorPropertyPane_spec.ts | 18 ++- app/client/src/ce/constants/messages.ts | 2 +- app/client/src/ce/utils/analyticsUtilTypes.ts | 24 +++- .../CustomWidgetAddEventButtonControl.tsx | 15 ++- .../CustomWidgetEditSourceButtonControl.tsx | 45 +++++--- .../Editor/Header/CodeTemplates/index.tsx | 52 ++++++++- .../Editor/Header/layoutControls.tsx | 14 ++- .../Editor/Header/referenceTrigger.tsx | 11 +- .../Editor/References/events.tsx | 8 +- .../Editor/References/styles.module.css | 3 + .../Preview/Debugger/index.tsx | 33 ++++-- .../CustomWidgetBuilder/Preview/index.tsx | 12 +- .../Editor/CustomWidgetBuilder/constants.ts | 4 + .../Editor/CustomWidgetBuilder/index.tsx | 28 ++++- .../pages/Editor/CustomWidgetBuilder/types.ts | 1 + .../Editor/PropertyPane/PropertyControl.tsx | 41 ++++++- .../Editor/PropertyPane/PropertyHelpLabel.tsx | 4 +- app/client/src/sagas/WidgetOperationSagas.tsx | 21 +++- .../src/utils/CustomWidgetBuilderService.ts | 8 +- .../widgets/ContainerWidget/widget/index.tsx | 3 +- .../CustomWidget/component/constants.ts | 15 ++- .../widgets/CustomWidget/component/index.tsx | 65 +++++++++-- .../widgets/CustomWidget/widget/defaultApp.ts | 15 +-- .../src/widgets/CustomWidget/widget/index.tsx | 106 ++++++++++++++++-- 24 files changed, 453 insertions(+), 95 deletions(-) diff --git a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Custom/CustomWidgetEditorPropertyPane_spec.ts b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Custom/CustomWidgetEditorPropertyPane_spec.ts index 0a8913142f..fb8c2636ce 100644 --- a/app/client/cypress/e2e/Regression/ClientSide/Widgets/Custom/CustomWidgetEditorPropertyPane_spec.ts +++ b/app/client/cypress/e2e/Regression/ClientSide/Widgets/Custom/CustomWidgetEditorPropertyPane_spec.ts @@ -11,22 +11,18 @@ describe( function () { before(() => { agHelper.AddDsl("customWidget"); - cy.wait(5000); }); const getIframeBody = () => { // get the iframe > document > body // and retry until the body element is not empty - return ( - cy - .get(".t--widget-customwidget iframe") - .its("0.contentDocument.body") - .should("not.be.empty") - // wraps "body" DOM element to allow - // chaining more Cypress commands, like ".find(...)" - // https://on.cypress.io/wrap - .then(cy.wrap) - ); + return cy + .get(".t--widget-customwidget iframe") + .its("0.contentDocument") + .should("exist") + .its("body") + .should("not.be.undefined") + .then(cy.wrap); }; it("shoud check that default model changes are converyed to custom component", () => { diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index 59cefc92a8..c7e018b77c 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -2375,7 +2375,7 @@ export const CUSTOM_WIDGET_FEATURE = { split: () => "Splits", }, referrences: { - title: () => "Referrences", + title: () => "References", tooltip: { open: () => "Open references", close: () => "Close references", diff --git a/app/client/src/ce/utils/analyticsUtilTypes.ts b/app/client/src/ce/utils/analyticsUtilTypes.ts index 9a77fddd04..5c586903af 100644 --- a/app/client/src/ce/utils/analyticsUtilTypes.ts +++ b/app/client/src/ce/utils/analyticsUtilTypes.ts @@ -350,7 +350,8 @@ export type EventName = | "START_FROM_TEMPLATES_CLICK_SKIP_BUTTON" | "SUPPORT_REQUEST_INITIATED" | ONBOARDING_FLOW_EVENTS - | CANVAS_STARTER_BUILDING_BLOCK_EVENTS; + | CANVAS_STARTER_BUILDING_BLOCK_EVENTS + | CUSTOM_WIDGET_EVENTS; export type CANVAS_STARTER_BUILDING_BLOCK_EVENTS = | "STARTER_BUILDING_BLOCK_HOVER" @@ -429,3 +430,24 @@ export type VERSION_UPDATE_EVENTS = | "VERSION_UPDATE_REQUESTED" | "VERSION_UPDATE_SUCCESS" | "VERSION_UPDATED_FAILED"; + +export type CUSTOM_WIDGET_EVENTS = + | "CUSTOM_WIDGET_EDIT_SOURCE_CLICKED" + | "CUSTOM_WIDGET_ADD_EVENT_CLICKED" + | "CUSTOM_WIDGET_ADD_EVENT_CANCEL_CLICKED" + | "CUSTOM_WIDGET_ADD_EVENT_SAVE_CLICKED" + | "CUSTOM_WIDGET_EDIT_EVENT_CLICKED" + | "CUSTOM_WIDGET_DELETE_EVENT_CLICKED" + | "CUSTOM_WIDGET_EDIT_EVENT_SAVE_CLICKED" + | "CUSTOM_WIDGET_EDIT_EVENT_CANCEL_CLICKED" + | "CUSTOM_WIDGET_BUILDER_SRCDOC_UPDATE" + | "CUSTOM_WIDGET_BUILDER_TEMPLATE_OPENED" + | "CUSTOM_WIDGET_BUILDER_TEMPLATE_REVERT_TO_ORIGINAL_CLICKED" + | "CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT" + | "CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CANCELED" + | "CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CONFIRMED" + | "CUSTOM_WIDGET_BUILDER_LAYOUT_CHANGED" + | "CUSTOM_WIDGET_BUILDER_REFERENCE_VISIBILITY_CHANGED" + | "CUSTOM_WIDGET_BUILDER_REFERENCE_EVENT_OPENED" + | "CUSTOM_WIDGET_BUILDER_DEBUGGER_CLEARED" + | "CUSTOM_WIDGET_BUILDER_DEBUGGER_VISIBILITY_CHANGED"; diff --git a/app/client/src/components/propertyControls/CustomWidgetAddEventButtonControl.tsx b/app/client/src/components/propertyControls/CustomWidgetAddEventButtonControl.tsx index d0b8aade0e..4a2e880251 100644 --- a/app/client/src/components/propertyControls/CustomWidgetAddEventButtonControl.tsx +++ b/app/client/src/components/propertyControls/CustomWidgetAddEventButtonControl.tsx @@ -9,6 +9,7 @@ import { CUSTOM_WIDGET_FEATURE, createMessage, } from "@appsmith/constants/messages"; +import AnalyticsUtil from "utils/AnalyticsUtil"; interface ButtonControlState { showInput: boolean; @@ -72,8 +73,12 @@ class ButtonControl extends BaseControl< reset = () => { this.setState({ showInput: false, eventName: "", pristine: true }); }; + onCancel = () => { this.reset(); + AnalyticsUtil.logEvent("CUSTOM_WIDGET_ADD_EVENT_CANCEL_CLICKED", { + widgetId: this.props.widgetProperties.widgetId, + }); }; onSave = () => { @@ -83,6 +88,9 @@ class ButtonControl extends BaseControl< ); this.batchUpdateProperties(updates); this.reset(); + AnalyticsUtil.logEvent("CUSTOM_WIDGET_ADD_EVENT_SAVE_CLICKED", { + widgetId: this.props.widgetProperties.widgetId, + }); }; hasError = () => { @@ -172,7 +180,12 @@ class ButtonControl extends BaseControl< ) : ( )} - +
{config.controlConfig?.allowEdit && ( - +
); @@ -93,8 +93,7 @@ appsmith.onReady(() => { height: calc(var(--appsmith-ui-height) * 1px); width: calc(var(--appsmith-ui-width) * 1px); justify-content: center; - border-radius: var(--appsmith-theme-borderRadius); - box-shadow: var(--appsmith-theme-boxShadow); + border-radius: 0px; } .tip-container { @@ -123,13 +122,14 @@ appsmith.onReady(() => { .button-container button { margin: 0 10px; + border-radius: var(--appsmith-theme-borderRadius) !important; } .button-container button.primary { background: var(--appsmith-theme-primaryColor) !important; } -.button-container button.reset { +.button-container button.reset:not([disabled]) { color: var(--appsmith-theme-primaryColor) !important; border-color: var(--appsmith-theme-primaryColor) !important; }`, @@ -161,6 +161,7 @@ function App() { type: "primary" }, "Next Tip"), /*#__PURE__*/React.createElement(Button, { className: "reset", + disabled: currentIndex === 0, onClick: handleReset }, "Reset"))); } diff --git a/app/client/src/widgets/CustomWidget/widget/index.tsx b/app/client/src/widgets/CustomWidget/widget/index.tsx index 7eb91aaacf..2b370b5ff0 100644 --- a/app/client/src/widgets/CustomWidget/widget/index.tsx +++ b/app/client/src/widgets/CustomWidget/widget/index.tsx @@ -8,9 +8,13 @@ import BaseWidget from "widgets/BaseWidget"; import CustomComponent from "../component"; import IconSVG from "../icon.svg"; -import { RenderModes, WIDGET_TAGS } from "constants/WidgetConstants"; +import { WIDGET_TAGS } from "constants/WidgetConstants"; import { ValidationTypes } from "constants/WidgetValidation"; -import type { AppThemeProperties, SetterConfig } from "entities/AppTheming"; +import type { + AppThemeProperties, + SetterConfig, + Stylesheet, +} from "entities/AppTheming"; import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils"; import type { AutocompletionDefinitions } from "WidgetProvider/constants"; import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag"; @@ -19,9 +23,14 @@ import { DEFAULT_MODEL } from "../constants"; import defaultApp from "./defaultApp"; import type { ExtraDef } from "utils/autocomplete/defCreatorUtils"; import { generateTypeDef } from "utils/autocomplete/defCreatorUtils"; -import { CUSTOM_WIDGET_DOC_URL } from "pages/Editor/CustomWidgetBuilder/constants"; +import { + CUSTOM_WIDGET_DEFAULT_MODEL_DOC_URL, + CUSTOM_WIDGET_DOC_URL, +} from "pages/Editor/CustomWidgetBuilder/constants"; import { Link } from "design-system"; import styled from "styled-components"; +import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; +import { Colors } from "constants/Colors"; const StyledLink = styled(Link)` display: inline-block; @@ -52,7 +61,7 @@ class CustomWidget extends BaseWidget { return { widgetName: "Custom", rows: 30, - columns: 20, + columns: 23, version: 1, onResetClick: "{{showAlert('Successfully reset!!', '');}}", events: ["onResetClick"], @@ -62,6 +71,9 @@ class CustomWidget extends BaseWidget { uncompiledSrcDoc: defaultApp.uncompiledSrcDoc, theme: "{{appsmith.theme}}", dynamicBindingPathList: [{ key: "theme" }], + borderColor: Colors.GREY_5, + borderWidth: "1", + backgroundColor: "#FFFFFF", }; } @@ -83,6 +95,13 @@ class CustomWidget extends BaseWidget { }; } + static getStylesheetConfig(): Stylesheet { + return { + borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}", + boxShadow: "{{appsmith.theme.boxShadow.appBoxShadow}}", + }; + } + static getPropertyPaneContentConfig() { return [ { @@ -126,7 +145,7 @@ class CustomWidget extends BaseWidget { kind="secondary" rel="noopener noreferrer" target="_blank" - to={CUSTOM_WIDGET_DOC_URL} + to={CUSTOM_WIDGET_DEFAULT_MODEL_DOC_URL} > Read more @@ -190,6 +209,7 @@ class CustomWidget extends BaseWidget { }, }, dependencies: ["events"], + helpText: "when the event is triggered from custom widget", })); }, children: [ @@ -217,7 +237,71 @@ class CustomWidget extends BaseWidget { } static getPropertyPaneStyleConfig() { - return []; + return [ + { + sectionName: "Color", + children: [ + { + helpText: "Use a html color name, HEX, RGB or RGBA value", + placeholderText: "#FFFFFF / Gray / rgb(255, 99, 71)", + propertyName: "backgroundColor", + label: "Background color", + controlType: "COLOR_PICKER", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.TEXT }, + }, + { + helpText: "Use a html color name, HEX, RGB or RGBA value", + placeholderText: "#FFFFFF / Gray / rgb(255, 99, 71)", + propertyName: "borderColor", + label: "Border color", + controlType: "COLOR_PICKER", + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.TEXT }, + }, + ], + }, + { + sectionName: "Border and shadow", + children: [ + { + helpText: "Enter value for border width", + propertyName: "borderWidth", + label: "Border width", + placeholderText: "Enter value in px", + controlType: "INPUT_TEXT", + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.NUMBER }, + postUpdateAction: ReduxActionTypes.CHECK_CONTAINERS_FOR_AUTO_HEIGHT, + }, + { + propertyName: "borderRadius", + label: "Border radius", + helpText: "Rounds the corners of the widgets's outer border edge", + controlType: "BORDER_RADIUS_OPTIONS", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.TEXT }, + }, + { + propertyName: "boxShadow", + label: "Box shadow", + helpText: + "Enables you to cast a drop shadow from the frame of the widget", + controlType: "BOX_SHADOW_OPTIONS", + isJSConvertible: true, + isBindProperty: true, + isTriggerProperty: false, + validation: { type: ValidationTypes.TEXT }, + }, + ], + }, + ]; } static getDerivedPropertiesMap(): DerivedPropertiesMap { @@ -270,17 +354,19 @@ class CustomWidget extends BaseWidget { getWidgetView() { return ( );