From f376d362e4f6e11dce23063a04d692b28cb5eae9 Mon Sep 17 00:00:00 2001 From: balajisoundar Date: Wed, 17 Jan 2024 19:44:14 +0530 Subject: [PATCH] chore: custom widget onReady warning and template updates (#30335) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Update tempaltes and add warning message when onReady function is missing. > if no issue exists, please create an issue and ask the maintainers about this first > > #### 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** - Introduced a new Vanilla JavaScript template for custom widgets. - Enhanced Vue.js custom widget template with new design and functionality. - Added a warning system to alert users when certain expected code patterns are missing. - **Bug Fixes** - Updated the `appsmithConsole` to include error handling. - **Documentation** - Added new documentation URLs for custom widget development guidance. - **Refactor** - Replaced the `blank` module with `vanillaJs` in code templates. - Removed unused styles and code comments from React template. - Streamlined default context values for widget development. --- app/client/src/ce/constants/messages.ts | 3 + app/client/src/ce/utils/analyticsUtilTypes.ts | 5 +- .../Header/CodeTemplates/Templates/blank.ts | 13 -- .../Header/CodeTemplates/Templates/index.ts | 4 +- .../Header/CodeTemplates/Templates/react.ts | 98 ++----------- .../CodeTemplates/Templates/vanillaJs.ts | 129 ++++++++++++++++++ .../Header/CodeTemplates/Templates/vue.ts | 125 ++++++++++++++--- .../Editor/CustomWidgetBuilder/constants.ts | 15 +- .../CustomWidgetBuilder/utility.test.ts | 4 +- .../Editor/CustomWidgetBuilder/utility.ts | 25 ++++ .../CustomWidget/component/appsmithConsole.js | 2 +- .../widgets/CustomWidget/component/index.tsx | 11 ++ .../widgets/CustomWidget/widget/defaultApp.ts | 7 + .../src/widgets/CustomWidget/widget/index.tsx | 10 ++ 14 files changed, 317 insertions(+), 134 deletions(-) delete mode 100644 app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/blank.ts create mode 100644 app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vanillaJs.ts diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index c7e018b77c..72a538d10d 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -2356,6 +2356,7 @@ export const CUSTOM_WIDGET_FEATURE = { }, templateKey: { blank: () => "Blank", + vanillaJs: () => "Vanilla JS", react: () => "React", vue: () => "Vue", }, @@ -2411,6 +2412,8 @@ export const CUSTOM_WIDGET_FEATURE = { helpDropdown: { stackoverflow: () => "Search StackOverflow", }, + noOnReadyWarning: (url: string) => + `Missing appsmith.onReady() function call. Initiate your component inside 'appsmith.onReady()' for your custom widget to work as expected. For more information - ${url}`, }, preview: { eventFired: () => "Event fired:", diff --git a/app/client/src/ce/utils/analyticsUtilTypes.ts b/app/client/src/ce/utils/analyticsUtilTypes.ts index 5c586903af..832299c110 100644 --- a/app/client/src/ce/utils/analyticsUtilTypes.ts +++ b/app/client/src/ce/utils/analyticsUtilTypes.ts @@ -432,6 +432,7 @@ export type VERSION_UPDATE_EVENTS = | "VERSION_UPDATED_FAILED"; export type CUSTOM_WIDGET_EVENTS = + | "CUSTOM_WIDGET_LOAD_INIT" | "CUSTOM_WIDGET_EDIT_SOURCE_CLICKED" | "CUSTOM_WIDGET_ADD_EVENT_CLICKED" | "CUSTOM_WIDGET_ADD_EVENT_CANCEL_CLICKED" @@ -450,4 +451,6 @@ export type CUSTOM_WIDGET_EVENTS = | "CUSTOM_WIDGET_BUILDER_REFERENCE_VISIBILITY_CHANGED" | "CUSTOM_WIDGET_BUILDER_REFERENCE_EVENT_OPENED" | "CUSTOM_WIDGET_BUILDER_DEBUGGER_CLEARED" - | "CUSTOM_WIDGET_BUILDER_DEBUGGER_VISIBILITY_CHANGED"; + | "CUSTOM_WIDGET_BUILDER_DEBUGGER_VISIBILITY_CHANGED" + | "CUSTOM_WIDGET_API_TRIGGER_EVENT" + | "CUSTOM_WIDGET_API_UPDATE_MODEL"; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/blank.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/blank.ts deleted file mode 100644 index 4b930114d7..0000000000 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/blank.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { - CUSTOM_WIDGET_FEATURE, - createMessage, -} from "@appsmith/constants/messages"; - -export default { - key: createMessage(CUSTOM_WIDGET_FEATURE.templateKey.blank), - uncompiledSrcDoc: { - html: "", - css: "", - js: "", - }, -}; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/index.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/index.ts index 9825b6ec1e..8174339fad 100644 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/index.ts +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/index.ts @@ -1,5 +1,5 @@ -import blank from "./blank"; +import vanillaJs from "./vanillaJs"; import react from "./react"; import vue from "./vue"; -export default [blank, react, vue]; +export default [vanillaJs, react, vue]; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/react.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/react.ts index 8f944018c8..251c42d166 100644 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/react.ts +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/react.ts @@ -2,6 +2,7 @@ import { CUSTOM_WIDGET_FEATURE, createMessage, } from "@appsmith/constants/messages"; +import { CUSTOM_WIDGET_ONREADY_DOC_URL } from "pages/Editor/CustomWidgetBuilder/constants"; export default { key: createMessage(CUSTOM_WIDGET_FEATURE.templateKey.react), @@ -43,6 +44,7 @@ export default { .button-container button { margin: 0 10px; + border-radius: var(--appsmith-theme-borderRadius); } .button-container button.primary { @@ -58,10 +60,6 @@ import reactDom from 'https://cdn.jsdelivr.net/npm/react-dom@18.2.0/+esm' import { Button, Card } from 'https://cdn.jsdelivr.net/npm/antd@5.11.1/+esm' import Markdown from 'https://cdn.jsdelivr.net/npm/react-markdown@9.0.1/+esm' -const style = { - maxWidth: "400px", -} - function App() { const [currentIndex, setCurrentIndex] = React.useState(0); @@ -75,7 +73,7 @@ function App() { }; return ( - +

Custom Widget

@@ -92,92 +90,12 @@ function App() { } appsmith.onReady(() => { + /* + * This handler function will get called when parent application is ready. + * Initialize your component here + * more info - ${CUSTOM_WIDGET_ONREADY_DOC_URL} + */ reactDom.render(, document.getElementById("root")); -});`, - }, - srcDoc: { - html: ` -
-`, - css: `.app { - 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); -} - -.tip-container { - margin-bottom: 20px; -} - -.tip-container h2 { - margin-bottom: 20px; - font-size: 16px; - font-weight: 700; -} - -.tip-header { - display: flex; - justify-content: space-between; - align-items: baseline; -} - -.tip-header div { - color: #999; -} - -.button-container { - text-align: right; -} - -.button-container button { - margin: 0 10px; -} - -.button-container button.primary { - background: var(--appsmith-theme-primaryColor) !important; -} - -.button-container button.reset { - color: var(--appsmith-theme-primaryColor) !important; - border-color: var(--appsmith-theme-primaryColor) !important; -}`, - js: `import React from 'https://cdn.jsdelivr.net/npm/react@18.2.0/+esm'; -import reactDom from 'https://cdn.jsdelivr.net/npm/react-dom@18.2.0/+esm'; -import { Button, Card } from 'https://cdn.jsdelivr.net/npm/antd@5.11.1/+esm'; -import Markdown from 'https://cdn.jsdelivr.net/npm/react-markdown@9.0.1/+esm'; -const style = { - maxWidth: "400px" -}; -function App() { - const [currentIndex, setCurrentIndex] = React.useState(0); - const handleNext = () => { - setCurrentIndex(prevIndex => (prevIndex + 1) % appsmith.model.tips.length); - }; - const handleReset = () => { - setCurrentIndex(0); - appsmith.triggerEvent("onReset"); - }; - return /*#__PURE__*/React.createElement(Card, { - className: "app", - style: style - }, /*#__PURE__*/React.createElement("div", { - className: "tip-container" - }, /*#__PURE__*/React.createElement("div", { - className: "tip-header" - }, /*#__PURE__*/React.createElement("h2", null, "Custom Widget"), /*#__PURE__*/React.createElement("div", null, currentIndex + 1, " / ", appsmith.model.tips.length, " ")), /*#__PURE__*/React.createElement(Markdown, null, appsmith.model.tips[currentIndex])), /*#__PURE__*/React.createElement("div", { - className: "button-container" - }, /*#__PURE__*/React.createElement(Button, { - className: "primary", - onClick: handleNext, - type: "primary" - }, "Next Tip"), /*#__PURE__*/React.createElement(Button, { - onClick: handleReset - }, "Reset"))); -} -appsmith.onReady(() => { - reactDom.render( /*#__PURE__*/React.createElement(App, null), document.getElementById("root")); });`, }, }; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vanillaJs.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vanillaJs.ts new file mode 100644 index 0000000000..e86786d4c6 --- /dev/null +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vanillaJs.ts @@ -0,0 +1,129 @@ +import { + CUSTOM_WIDGET_FEATURE, + createMessage, +} from "@appsmith/constants/messages"; +import { CUSTOM_WIDGET_ONREADY_DOC_URL } from "pages/Editor/CustomWidgetBuilder/constants"; + +export default { + key: createMessage(CUSTOM_WIDGET_FEATURE.templateKey.vanillaJs), + uncompiledSrcDoc: { + html: `
+
+
+

Custom Widget

+
+
+
+
+
+ + +
+
`, + css: `.app { + 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); + padding: 29px 25px; + box-sizing: border-box; + font-family: system-ui; + background: #fff; +} + +.tip-container { + margin-bottom: 20px; + font-size: 14px; + line-height: 1.571429; +} + +.tip-container h2 { + margin-bottom: 20px; + font-size: 16px; + font-weight: 700; +} + +.tip-header { + display: flex; + justify-content: space-between; + align-items: baseline; + margin-bottom: 9px; +} + +.tip-header div { + color: #999; +} + +.button-container { + text-align: right; + padding-top: 4px; +} + +.button-container button { + margin: 0 10px; + cursor: pointer; + border-radius: var(--appsmith-theme-borderRadius); + padding: 6px 16px; + background: none; +} + +.button-container button#next { + background: var(--appsmith-theme-primaryColor) !important; + color: #fff; + border:1px solid var(--appsmith-theme-primaryColor) !important; +} + +.button-container button#reset { + border: 1px solid #999; + color: #999; + outline: none; + box-shadow: none; +} + +.button-container button#reset:hover:not(:disabled) { + color: var(--appsmith-theme-primaryColor); + border-color: var(--appsmith-theme-primaryColor); +} + +.button-container button#reset:disabled { + cursor: default; +}`, + js: `function initApp() { + const index = document.getElementById("index"); + const tip = document.getElementById("tip"); + const next = document.getElementById("next"); + const reset = document.getElementById("reset"); + + let currentIndex = 0; + + const updateDom = () => { + tip.innerHTML = appsmith.model.tips[currentIndex]; + index.innerHTML = (currentIndex + 1) + " / " + appsmith.model.tips.length; + reset.disabled = currentIndex === 0; + }; + + next.addEventListener("click", () => { + currentIndex = (currentIndex + 1) % appsmith.model.tips.length; + updateDom(); + }); + + reset.addEventListener("click", () => { + currentIndex = 0; + updateDom(); + appsmith.triggerEvent("onReset"); + }); + + updateDom(); +} + +appsmith.onReady(() => { + /* + * This handler function will get called when parent application is ready. + * Initialize your component here + * more info - ${CUSTOM_WIDGET_ONREADY_DOC_URL} + */ + initApp(); +});`, + }, +}; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vue.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vue.ts index 8506b6b9c4..440e54d3a5 100644 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vue.ts +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/Editor/Header/CodeTemplates/Templates/vue.ts @@ -2,31 +2,118 @@ import { CUSTOM_WIDGET_FEATURE, createMessage, } from "@appsmith/constants/messages"; +import { CUSTOM_WIDGET_ONREADY_DOC_URL } from "pages/Editor/CustomWidgetBuilder/constants"; export default { key: createMessage(CUSTOM_WIDGET_FEATURE.templateKey.vue), uncompiledSrcDoc: { - html: `
-

{{ msg }}

+ html: `
+
+
+

Custom Widget

+
{{ currentIndex + 1 }} / {{ tips.length }}
+
+
{{ tips[currentIndex] }}
+
+
+ + +
-`, - css: `#hello-world-app { - font-family: monospace; - width: 100vw; - height: 100vh; - display: flex; - justify-content: center; - align-items: center; +`, + css: `#app { + 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); + padding: 29px 25px; + box-sizing: border-box; + font-family: system-ui; + background: #fff; +} + +.tip-container { + margin-bottom: 20px; + font-size: 14px; + line-height: 1.571429; +} + +.tip-container h2 { + margin-bottom: 20px; + font-size: 16px; + font-weight: 700; +} + +.tip-header { + display: flex; + justify-content: space-between; + align-items: baseline; + margin-bottom: 9px; +} + +.tip-header div { + color: #999; +} + +.button-container { + text-align: right; + padding-top: 4px; +} + +.button-container button { + margin: 0 10px; + cursor: pointer; + border-radius: var(--appsmith-theme-borderRadius); + padding: 6px 16px; + background: none; +} + +.button-container button#next { + background: var(--appsmith-theme-primaryColor) !important; + color: #fff; + border:1px solid var(--appsmith-theme-primaryColor) !important; +} + +.button-container button#reset { + border: 1px solid #999; + color: #999; + outline: none; + box-shadow: none; +} + +.button-container button#reset:hover:not(:disabled) { + color: var(--appsmith-theme-primaryColor); + border-color: var(--appsmith-theme-primaryColor); +} + +.button-container button#reset:disabled { + cursor: default; }`, - js: `new Vue({ - el: "#hello-world-app", - data() { - return { - msg: "Hello World by Vue!" - } - } + js: `appsmith.onReady(() => { + /* + * This handler function will get called when parent application is ready. + * Initialize your component here + * more info - ${CUSTOM_WIDGET_ONREADY_DOC_URL} + */ + new Vue({ + el: "#app", + data() { + return { + currentIndex: 0, + tips: appsmith.model.tips, + }; + }, + methods: { + next() { + this.currentIndex = (this.currentIndex + 1) % this.tips.length; + }, + reset() { + this.currentIndex = 0; + appsmith.triggerEvent("onReset"); + }, + }, + }); });`, }, }; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/constants.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/constants.ts index 42941c6bbd..23a74e2500 100644 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/constants.ts +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/constants.ts @@ -21,14 +21,14 @@ export const DEFAULT_CONTEXT_VALUE = { name: "", widgetId: "", srcDoc: { - html: "
Hello World
", - js: "function test() {console.log('Hello World');}", - css: "div {color: red;}", + html: "", + js: "", + css: "", }, uncompiledSrcDoc: { - html: "
Hello World
", - js: "function test() {console.log('Hello World');}", - css: "div {color: red;}", + html: "", + js: "", + css: "", }, model: {}, events: {}, @@ -59,3 +59,6 @@ export const CUSTOM_WIDGET_DOC_URL = export const CUSTOM_WIDGET_DEFAULT_MODEL_DOC_URL = "https://docs.appsmith.com/reference/widgets/custom#default-model"; + +export const CUSTOM_WIDGET_ONREADY_DOC_URL = + "https://docs.appsmith.com/reference/widgets/custom#onready"; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/utility.test.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/utility.test.ts index e1abfb4e7b..fa44efd508 100644 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/utility.test.ts +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/utility.test.ts @@ -56,14 +56,14 @@ describe("compileSrcDoc", () => { const result = compileSrcDoc(validSrcDoc); expect(result.code).toEqual(validSrcDoc); - expect(result.warnings).toHaveLength(0); + expect(result.warnings).toHaveLength(1); expect(result.errors).toHaveLength(0); }); it("should handle Babel compilation errors", () => { const srcDocWithErrors = { html: "
Hello World
", - js: "const a = 5 )", + js: "appsmith.onReady(() => {const a = 5 )})", css: "div { color: red; }", }; diff --git a/app/client/src/pages/Editor/CustomWidgetBuilder/utility.ts b/app/client/src/pages/Editor/CustomWidgetBuilder/utility.ts index 0a2f3f0b32..9803273187 100644 --- a/app/client/src/pages/Editor/CustomWidgetBuilder/utility.ts +++ b/app/client/src/pages/Editor/CustomWidgetBuilder/utility.ts @@ -1,5 +1,10 @@ import { transform } from "@babel/standalone/"; import type { DebuggerLogItem, SrcDoc } from "./types"; +import { + CUSTOM_WIDGET_FEATURE, + createMessage, +} from "@appsmith/constants/messages"; +import { CUSTOM_WIDGET_ONREADY_DOC_URL } from "./constants"; interface CompiledResult { code: SrcDoc; @@ -14,6 +19,8 @@ export const compileSrcDoc = (srcDoc: SrcDoc): CompiledResult => { errors: [], }; + checkForWarnings(compiledResult); + try { const result = transform(srcDoc.js, { sourceType: "module", @@ -34,6 +41,24 @@ export const compileSrcDoc = (srcDoc: SrcDoc): CompiledResult => { return compiledResult; }; +function checkForWarnings(compiledResult: CompiledResult) { + const code = compiledResult.code.js; + + if (code?.length > 0) { + /* + * We are keeping this check as a simple string check instead of using AST + * because we want to keep the custom widget compile process as simple as possible. + */ + !code.includes("appsmith.onReady(") && + compiledResult.warnings.push({ + message: createMessage( + CUSTOM_WIDGET_FEATURE.debugger.noOnReadyWarning, + CUSTOM_WIDGET_ONREADY_DOC_URL, + ), + }); + } +} + export interface BabelError { reasonCode: string; message: string; diff --git a/app/client/src/widgets/CustomWidget/component/appsmithConsole.js b/app/client/src/widgets/CustomWidget/component/appsmithConsole.js index 1c27b1b5eb..1f68e5ed4a 100644 --- a/app/client/src/widgets/CustomWidget/component/appsmithConsole.js +++ b/app/client/src/widgets/CustomWidget/component/appsmithConsole.js @@ -25,7 +25,7 @@ }, }); - ["log", "warn", "info"].forEach((method) => { + ["log", "warn", "info", "error"].forEach((method) => { nativeConsole[method] = createProxy(method); }); diff --git a/app/client/src/widgets/CustomWidget/component/index.tsx b/app/client/src/widgets/CustomWidget/component/index.tsx index 82f29e6b0a..149b9b7612 100644 --- a/app/client/src/widgets/CustomWidget/component/index.tsx +++ b/app/client/src/widgets/CustomWidget/component/index.tsx @@ -23,6 +23,7 @@ import { combinedPreviewModeSelector } from "selectors/editorSelectors"; import { getAppMode } from "@appsmith/selectors/applicationSelectors"; import { APP_MODE } from "entities/App"; import { getWidgetPropsForPropertyPane } from "selectors/propertyPaneSelectors"; +import AnalyticsUtil from "utils/AnalyticsUtil"; const StyledIframe = styled.iframe<{ width: number; height: number }>` width: ${(props) => props.width - 8}px; @@ -101,6 +102,16 @@ function CustomComponent(props: CustomComponentProps) { }, "*", ); + + if ( + props.renderMode === "DEPLOYED" || + props.renderMode === "EDITOR" + ) { + AnalyticsUtil.logEvent("CUSTOM_WIDGET_LOAD_INIT", { + widgetId: props.widgetId, + renderMode: props.renderMode, + }); + } break; case EVENTS.CUSTOM_WIDGET_UPDATE_MODEL: props.update(message.data); diff --git a/app/client/src/widgets/CustomWidget/widget/defaultApp.ts b/app/client/src/widgets/CustomWidget/widget/defaultApp.ts index d98fb154eb..4451d46fd0 100644 --- a/app/client/src/widgets/CustomWidget/widget/defaultApp.ts +++ b/app/client/src/widgets/CustomWidget/widget/defaultApp.ts @@ -1,3 +1,5 @@ +import { CUSTOM_WIDGET_ONREADY_DOC_URL } from "pages/Editor/CustomWidgetBuilder/constants"; + export default { uncompiledSrcDoc: { html: ` @@ -82,6 +84,11 @@ function App() { } appsmith.onReady(() => { + /* + * This handler function will get called when parent application is ready. + * Initialize your component here + * more info - ${CUSTOM_WIDGET_ONREADY_DOC_URL} + */ reactDom.render(, document.getElementById("root")); });`, }, diff --git a/app/client/src/widgets/CustomWidget/widget/index.tsx b/app/client/src/widgets/CustomWidget/widget/index.tsx index 2b370b5ff0..d943782935 100644 --- a/app/client/src/widgets/CustomWidget/widget/index.tsx +++ b/app/client/src/widgets/CustomWidget/widget/index.tsx @@ -31,6 +31,7 @@ import { Link } from "design-system"; import styled from "styled-components"; import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants"; import { Colors } from "constants/Colors"; +import AnalyticsUtil from "utils/AnalyticsUtil"; const StyledLink = styled(Link)` display: inline-block; @@ -332,6 +333,11 @@ class CustomWidget extends BaseWidget { }, globalContext: contextObj, }); + + AnalyticsUtil.logEvent("CUSTOM_WIDGET_API_TRIGGER_EVENT", { + widgetId: this.props.widgetId, + eventName, + }); } }; @@ -340,6 +346,10 @@ class CustomWidget extends BaseWidget { ...this.props.model, ...data, }); + + AnalyticsUtil.logEvent("CUSTOM_WIDGET_API_UPDATE_MODEL", { + widgetId: this.props.widgetId, + }); }; getRenderMode = () => {