chore: misc updates to custom widget (#30114)
#### 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 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## 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. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
8bb61d996a
commit
5d44d4f2cf
|
|
@ -11,22 +11,18 @@ describe(
|
||||||
function () {
|
function () {
|
||||||
before(() => {
|
before(() => {
|
||||||
agHelper.AddDsl("customWidget");
|
agHelper.AddDsl("customWidget");
|
||||||
cy.wait(5000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const getIframeBody = () => {
|
const getIframeBody = () => {
|
||||||
// get the iframe > document > body
|
// get the iframe > document > body
|
||||||
// and retry until the body element is not empty
|
// and retry until the body element is not empty
|
||||||
return (
|
return cy
|
||||||
cy
|
.get(".t--widget-customwidget iframe")
|
||||||
.get(".t--widget-customwidget iframe")
|
.its("0.contentDocument")
|
||||||
.its("0.contentDocument.body")
|
.should("exist")
|
||||||
.should("not.be.empty")
|
.its("body")
|
||||||
// wraps "body" DOM element to allow
|
.should("not.be.undefined")
|
||||||
// chaining more Cypress commands, like ".find(...)"
|
.then(cy.wrap);
|
||||||
// https://on.cypress.io/wrap
|
|
||||||
.then(cy.wrap)
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
it("shoud check that default model changes are converyed to custom component", () => {
|
it("shoud check that default model changes are converyed to custom component", () => {
|
||||||
|
|
|
||||||
|
|
@ -2375,7 +2375,7 @@ export const CUSTOM_WIDGET_FEATURE = {
|
||||||
split: () => "Splits",
|
split: () => "Splits",
|
||||||
},
|
},
|
||||||
referrences: {
|
referrences: {
|
||||||
title: () => "Referrences",
|
title: () => "References",
|
||||||
tooltip: {
|
tooltip: {
|
||||||
open: () => "Open references",
|
open: () => "Open references",
|
||||||
close: () => "Close references",
|
close: () => "Close references",
|
||||||
|
|
|
||||||
|
|
@ -350,7 +350,8 @@ export type EventName =
|
||||||
| "START_FROM_TEMPLATES_CLICK_SKIP_BUTTON"
|
| "START_FROM_TEMPLATES_CLICK_SKIP_BUTTON"
|
||||||
| "SUPPORT_REQUEST_INITIATED"
|
| "SUPPORT_REQUEST_INITIATED"
|
||||||
| ONBOARDING_FLOW_EVENTS
|
| ONBOARDING_FLOW_EVENTS
|
||||||
| CANVAS_STARTER_BUILDING_BLOCK_EVENTS;
|
| CANVAS_STARTER_BUILDING_BLOCK_EVENTS
|
||||||
|
| CUSTOM_WIDGET_EVENTS;
|
||||||
|
|
||||||
export type CANVAS_STARTER_BUILDING_BLOCK_EVENTS =
|
export type CANVAS_STARTER_BUILDING_BLOCK_EVENTS =
|
||||||
| "STARTER_BUILDING_BLOCK_HOVER"
|
| "STARTER_BUILDING_BLOCK_HOVER"
|
||||||
|
|
@ -429,3 +430,24 @@ export type VERSION_UPDATE_EVENTS =
|
||||||
| "VERSION_UPDATE_REQUESTED"
|
| "VERSION_UPDATE_REQUESTED"
|
||||||
| "VERSION_UPDATE_SUCCESS"
|
| "VERSION_UPDATE_SUCCESS"
|
||||||
| "VERSION_UPDATED_FAILED";
|
| "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";
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import {
|
||||||
CUSTOM_WIDGET_FEATURE,
|
CUSTOM_WIDGET_FEATURE,
|
||||||
createMessage,
|
createMessage,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
interface ButtonControlState {
|
interface ButtonControlState {
|
||||||
showInput: boolean;
|
showInput: boolean;
|
||||||
|
|
@ -72,8 +73,12 @@ class ButtonControl extends BaseControl<
|
||||||
reset = () => {
|
reset = () => {
|
||||||
this.setState({ showInput: false, eventName: "", pristine: true });
|
this.setState({ showInput: false, eventName: "", pristine: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
onCancel = () => {
|
onCancel = () => {
|
||||||
this.reset();
|
this.reset();
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_ADD_EVENT_CANCEL_CLICKED", {
|
||||||
|
widgetId: this.props.widgetProperties.widgetId,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onSave = () => {
|
onSave = () => {
|
||||||
|
|
@ -83,6 +88,9 @@ class ButtonControl extends BaseControl<
|
||||||
);
|
);
|
||||||
this.batchUpdateProperties(updates);
|
this.batchUpdateProperties(updates);
|
||||||
this.reset();
|
this.reset();
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_ADD_EVENT_SAVE_CLICKED", {
|
||||||
|
widgetId: this.props.widgetProperties.widgetId,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
hasError = () => {
|
hasError = () => {
|
||||||
|
|
@ -172,7 +180,12 @@ class ButtonControl extends BaseControl<
|
||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
kind="tertiary"
|
kind="tertiary"
|
||||||
onClick={() => this.setState({ showInput: true })}
|
onClick={() => {
|
||||||
|
this.setState({ showInput: true });
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_ADD_EVENT_CLICKED", {
|
||||||
|
widgetId: this.props.widgetProperties.widgetId,
|
||||||
|
});
|
||||||
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
startIcon="plus"
|
startIcon="plus"
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import {
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
import CustomWidgetBuilderService from "utils/CustomWidgetBuilderService";
|
import CustomWidgetBuilderService from "utils/CustomWidgetBuilderService";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
interface ButtonControlState {
|
interface ButtonControlState {
|
||||||
isSourceEditorOpen: boolean;
|
isSourceEditorOpen: boolean;
|
||||||
|
|
@ -24,7 +25,32 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
||||||
isSourceEditorOpen: false,
|
isSourceEditorOpen: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
getPayload = () => {
|
||||||
|
return {
|
||||||
|
name: this.props.widgetProperties.widgetName,
|
||||||
|
widgetId: this.props.widgetProperties.widgetId,
|
||||||
|
srcDoc: this.props.widgetProperties.srcDoc,
|
||||||
|
uncompiledSrcDoc: this.props.widgetProperties.uncompiledSrcDoc,
|
||||||
|
model:
|
||||||
|
this.props.widgetProperties.__evaluation__?.evaluatedValues
|
||||||
|
?.defaultModel,
|
||||||
|
events: this.props.widgetProperties.events.reduce(
|
||||||
|
(prev: Record<string, string>, curr: string) => {
|
||||||
|
prev[curr] = this.props.widgetProperties[curr];
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
theme: this.props.widgetProperties.__evaluation__?.evaluatedValues?.theme,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
onCTAClick = () => {
|
onCTAClick = () => {
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_EDIT_SOURCE_CLICKED", {
|
||||||
|
widgetId: this.props.widgetProperties.widgetId,
|
||||||
|
});
|
||||||
|
|
||||||
if (
|
if (
|
||||||
CustomWidgetBuilderService.isConnected(
|
CustomWidgetBuilderService.isConnected(
|
||||||
this.props.widgetProperties.widgetId,
|
this.props.widgetProperties.widgetId,
|
||||||
|
|
@ -40,22 +66,7 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
||||||
onMessage(CUSTOM_WIDGET_BUILDER_EVENTS.READY, () => {
|
onMessage(CUSTOM_WIDGET_BUILDER_EVENTS.READY, () => {
|
||||||
postMessage({
|
postMessage({
|
||||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.READY_ACK,
|
type: CUSTOM_WIDGET_BUILDER_EVENTS.READY_ACK,
|
||||||
name: this.props.widgetProperties.widgetName,
|
...this.getPayload(),
|
||||||
srcDoc: this.props.widgetProperties.srcDoc,
|
|
||||||
uncompiledSrcDoc: this.props.widgetProperties.uncompiledSrcDoc,
|
|
||||||
model:
|
|
||||||
this.props.widgetProperties.__evaluation__?.evaluatedValues
|
|
||||||
?.defaultModel,
|
|
||||||
events: this.props.widgetProperties.events.reduce(
|
|
||||||
(prev: Record<string, string>, curr: string) => {
|
|
||||||
prev[curr] = this.props.widgetProperties[curr];
|
|
||||||
|
|
||||||
return prev;
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
theme:
|
|
||||||
this.props.widgetProperties.__evaluation__?.evaluatedValues?.theme,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -74,6 +85,7 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
||||||
onMessage(CUSTOM_WIDGET_BUILDER_EVENTS.DISCONNECTED, () => {
|
onMessage(CUSTOM_WIDGET_BUILDER_EVENTS.DISCONNECTED, () => {
|
||||||
CustomWidgetBuilderService.closeConnection(
|
CustomWidgetBuilderService.closeConnection(
|
||||||
this.props.widgetProperties.widgetId,
|
this.props.widgetProperties.widgetId,
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
|
@ -105,6 +117,7 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
||||||
this.props.widgetProperties.widgetId,
|
this.props.widgetProperties.widgetId,
|
||||||
)?.postMessage({
|
)?.postMessage({
|
||||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.RESUME,
|
type: CUSTOM_WIDGET_BUILDER_EVENTS.RESUME,
|
||||||
|
...this.getPayload(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import {
|
||||||
CUSTOM_WIDGET_FEATURE,
|
CUSTOM_WIDGET_FEATURE,
|
||||||
createMessage,
|
createMessage,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
const StyledButton = styled(Button)`
|
const StyledButton = styled(Button)`
|
||||||
height: 32px !important;
|
height: 32px !important;
|
||||||
|
|
@ -70,13 +71,14 @@ function ConfirmationModal(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CodeTemplates() {
|
export function CodeTemplates() {
|
||||||
const { bulkUpdate, initialSrcDoc, lastSaved } = useContext(
|
const { bulkUpdate, initialSrcDoc, lastSaved, widgetId } = useContext(
|
||||||
CustomWidgetBuilderContext,
|
CustomWidgetBuilderContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const [selectedTemplate, setSelectedTemplate] = useState<SrcDoc | null>(null);
|
const [selectedTemplate, setSelectedTemplate] = useState<SrcDoc | null>(null);
|
||||||
|
const [selectedTemplateName, setSelectedTemplateName] = useState("");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.templateMenu}>
|
<div className={styles.templateMenu}>
|
||||||
|
|
@ -85,9 +87,13 @@ export function CodeTemplates() {
|
||||||
<StyledButton
|
<StyledButton
|
||||||
className="t--custom-widget-template-trigger"
|
className="t--custom-widget-template-trigger"
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
|
onClick={() => {
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_TEMPLATE_OPENED", {
|
||||||
|
widgetId: widgetId,
|
||||||
|
});
|
||||||
|
}}
|
||||||
size="sm"
|
size="sm"
|
||||||
startIcon="query"
|
startIcon="query"
|
||||||
style={{}}
|
|
||||||
>
|
>
|
||||||
{createMessage(CUSTOM_WIDGET_FEATURE.template.buttonCTA)}
|
{createMessage(CUSTOM_WIDGET_FEATURE.template.buttonCTA)}
|
||||||
</StyledButton>
|
</StyledButton>
|
||||||
|
|
@ -98,7 +104,17 @@ export function CodeTemplates() {
|
||||||
<MenuItem
|
<MenuItem
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedTemplate(initialSrcDoc);
|
setSelectedTemplate(initialSrcDoc);
|
||||||
|
setSelectedTemplateName(
|
||||||
|
CUSTOM_WIDGET_FEATURE.template.revert,
|
||||||
|
);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT",
|
||||||
|
{
|
||||||
|
widgetId: widgetId,
|
||||||
|
templateName: CUSTOM_WIDGET_FEATURE.template.revert,
|
||||||
|
},
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{createMessage(CUSTOM_WIDGET_FEATURE.template.revert)}
|
{createMessage(CUSTOM_WIDGET_FEATURE.template.revert)}
|
||||||
|
|
@ -111,7 +127,15 @@ export function CodeTemplates() {
|
||||||
key={template.key}
|
key={template.key}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setSelectedTemplate(template.uncompiledSrcDoc);
|
setSelectedTemplate(template.uncompiledSrcDoc);
|
||||||
|
setSelectedTemplateName(template.key);
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT",
|
||||||
|
{
|
||||||
|
widgetId: widgetId,
|
||||||
|
templateName: template.key,
|
||||||
|
},
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{template.key}
|
{template.key}
|
||||||
|
|
@ -122,18 +146,42 @@ export function CodeTemplates() {
|
||||||
<ConfirmationModal
|
<ConfirmationModal
|
||||||
onCancel={() => {
|
onCancel={() => {
|
||||||
setSelectedTemplate(null);
|
setSelectedTemplate(null);
|
||||||
|
setSelectedTemplateName("");
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CANCELED",
|
||||||
|
{
|
||||||
|
widgetId: widgetId,
|
||||||
|
templateName: selectedTemplateName,
|
||||||
|
},
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
onOpenChange={(flag: boolean) => {
|
onOpenChange={(flag: boolean) => {
|
||||||
if (!flag) {
|
if (!flag) {
|
||||||
setSelectedTemplate(null);
|
setSelectedTemplate(null);
|
||||||
|
setSelectedTemplateName("");
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CANCELED",
|
||||||
|
{
|
||||||
|
widgetId: widgetId,
|
||||||
|
templateName: selectedTemplateName,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onReplace={() => {
|
onReplace={() => {
|
||||||
selectedTemplate && bulkUpdate?.(selectedTemplate);
|
selectedTemplate && bulkUpdate?.(selectedTemplate);
|
||||||
setSelectedTemplate(null);
|
setSelectedTemplate(null);
|
||||||
|
setSelectedTemplateName("");
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CONFIRMED",
|
||||||
|
{
|
||||||
|
widgetId: widgetId,
|
||||||
|
templateName: selectedTemplateName,
|
||||||
|
},
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
open={open}
|
open={open}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import {
|
||||||
CUSTOM_WIDGET_FEATURE,
|
CUSTOM_WIDGET_FEATURE,
|
||||||
createMessage,
|
createMessage,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
const StyledSegmentedControl = styled(SegmentedControl)`
|
const StyledSegmentedControl = styled(SegmentedControl)`
|
||||||
& .ads-v2-icon {
|
& .ads-v2-icon {
|
||||||
|
|
@ -15,10 +16,17 @@ const StyledSegmentedControl = styled(SegmentedControl)`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function LayoutControls() {
|
export default function LayoutControls() {
|
||||||
const context = useContext(CustomWidgetBuilderContext);
|
const { selectedLayout, selectLayout, widgetId } = useContext(
|
||||||
|
CustomWidgetBuilderContext,
|
||||||
|
);
|
||||||
|
|
||||||
const onChange = (value: string) => {
|
const onChange = (value: string) => {
|
||||||
context.selectLayout?.(value);
|
selectLayout?.(value);
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_LAYOUT_CHANGED", {
|
||||||
|
widgetId: widgetId,
|
||||||
|
layoutName: value,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
@ -37,7 +45,7 @@ export default function LayoutControls() {
|
||||||
value: "tabs",
|
value: "tabs",
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
value={context.selectedLayout}
|
value={selectedLayout}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,23 @@ import {
|
||||||
CUSTOM_WIDGET_FEATURE,
|
CUSTOM_WIDGET_FEATURE,
|
||||||
createMessage,
|
createMessage,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
export default function ReferenceTrigger() {
|
export default function ReferenceTrigger() {
|
||||||
const { isReferenceOpen, toggleReference } = useContext(
|
const { isReferenceOpen, toggleReference, widgetId } = useContext(
|
||||||
CustomWidgetBuilderContext,
|
CustomWidgetBuilderContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
toggleReference?.();
|
toggleReference?.();
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_BUILDER_REFERENCE_VISIBILITY_CHANGED",
|
||||||
|
{
|
||||||
|
widgetId: widgetId,
|
||||||
|
visible: !isReferenceOpen,
|
||||||
|
},
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import {
|
||||||
CUSTOM_WIDGET_FEATURE,
|
CUSTOM_WIDGET_FEATURE,
|
||||||
createMessage,
|
createMessage,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
const StyledLazyCodeEditorWrapper = styled.div`
|
const StyledLazyCodeEditorWrapper = styled.div`
|
||||||
.CodeMirror-line.CodeMirror-line {
|
.CodeMirror-line.CodeMirror-line {
|
||||||
|
|
@ -31,11 +32,16 @@ const StyledLazyCodeEditorWrapper = styled.div`
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export default function Events() {
|
export default function Events() {
|
||||||
const { events } = useContext(CustomWidgetBuilderContext);
|
const { events, widgetId } = useContext(CustomWidgetBuilderContext);
|
||||||
|
|
||||||
const [openState, setOpenState] = useState<Record<string, boolean>>({});
|
const [openState, setOpenState] = useState<Record<string, boolean>>({});
|
||||||
|
|
||||||
const toggleOpen = useCallback((event: string) => {
|
const toggleOpen = useCallback((event: string) => {
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_REFERENCE_EVENT_OPENED", {
|
||||||
|
widgetId: widgetId,
|
||||||
|
eventName: event,
|
||||||
|
});
|
||||||
|
|
||||||
setOpenState((prev) => {
|
setOpenState((prev) => {
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,9 @@
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
width: calc(100% - 22px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.eventControl {
|
.eventControl {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useContext, useEffect } from "react";
|
import React, { useCallback, useContext, useEffect } from "react";
|
||||||
import { Tabs, TabsList, Tab, TabPanel, Icon, Tooltip } from "design-system";
|
import { Tabs, TabsList, Tab, TabPanel, Icon, Tooltip } from "design-system";
|
||||||
import DebuggerItem from "./debuggerItem";
|
import DebuggerItem from "./debuggerItem";
|
||||||
import styles from "./styles.module.css";
|
import styles from "./styles.module.css";
|
||||||
|
|
@ -11,6 +11,7 @@ import {
|
||||||
CUSTOM_WIDGET_FEATURE,
|
CUSTOM_WIDGET_FEATURE,
|
||||||
createMessage,
|
createMessage,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
const LOCAL_STORAGE_KEYS_IS_DEBUGGER_OPEN =
|
const LOCAL_STORAGE_KEYS_IS_DEBUGGER_OPEN =
|
||||||
"custom-widget-builder-context-state-is-debugger-open";
|
"custom-widget-builder-context-state-is-debugger-open";
|
||||||
|
|
@ -23,7 +24,7 @@ export default function Debugger() {
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
const { clearDegbuggerLogs, debuggerLogs } = useContext(
|
const { clearDegbuggerLogs, debuggerLogs, widgetId } = useContext(
|
||||||
CustomWidgetBuilderContext,
|
CustomWidgetBuilderContext,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -31,6 +32,17 @@ export default function Debugger() {
|
||||||
scrollToRef.current?.scrollIntoView({ behavior: "smooth" });
|
scrollToRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||||
}, [debuggerLogs]);
|
}, [debuggerLogs]);
|
||||||
|
|
||||||
|
const toggle = useCallback(() => {
|
||||||
|
setOpen(!open);
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_BUILDER_DEBUGGER_VISIBILITY_CHANGED",
|
||||||
|
{
|
||||||
|
widgetId: widgetId,
|
||||||
|
visible: !open,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}, [open]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
<div className={styles.debuggerActions}>
|
<div className={styles.debuggerActions}>
|
||||||
|
|
@ -43,31 +55,36 @@ export default function Debugger() {
|
||||||
debuggerLogs?.filter((d) => d.type === DebuggerLogType.LOG)
|
debuggerLogs?.filter((d) => d.type === DebuggerLogType.LOG)
|
||||||
.length || 0
|
.length || 0
|
||||||
}
|
}
|
||||||
onClick={() => setOpen(!open)}
|
onClick={() => toggle()}
|
||||||
warn={
|
warn={
|
||||||
debuggerLogs?.filter((d) => d.type === DebuggerLogType.WARN)
|
debuggerLogs?.filter((d) => d.type === DebuggerLogType.WARN)
|
||||||
.length || 0
|
.length || 0
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Tooltip content="clear console">
|
<Tooltip content="Clear console">
|
||||||
<Icon
|
<Icon
|
||||||
name="forbid-line"
|
name="forbid-line"
|
||||||
onClick={() => clearDegbuggerLogs?.()}
|
onClick={() => {
|
||||||
|
clearDegbuggerLogs?.();
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_DEBUGGER_CLEARED", {
|
||||||
|
widgetId: widgetId,
|
||||||
|
});
|
||||||
|
}}
|
||||||
size="md"
|
size="md"
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<Tooltip content={open ? "close console" : "open console"}>
|
<Tooltip content={open ? "Close console" : "Open console"}>
|
||||||
<Icon
|
<Icon
|
||||||
name={open ? "arrow-down-s-line" : "arrow-up-s-line"}
|
name={open ? "arrow-down-s-line" : "arrow-up-s-line"}
|
||||||
onClick={() => setOpen(!open)}
|
onClick={() => toggle()}
|
||||||
size="lg"
|
size="lg"
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
<Tabs value={"Debugger"}>
|
<Tabs value={"Debugger"}>
|
||||||
<TabsList className={styles.debuggerTab} onClick={() => setOpen(!open)}>
|
<TabsList className={styles.debuggerTab} onClick={() => toggle()}>
|
||||||
<Tab key="Debugger" value="Debugger">
|
<Tab key="Debugger" value="Debugger">
|
||||||
{createMessage(CUSTOM_WIDGET_FEATURE.debugger.title)}
|
{createMessage(CUSTOM_WIDGET_FEATURE.debugger.title)}
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,15 @@ import {
|
||||||
import type { AppThemeProperties } from "entities/AppTheming";
|
import type { AppThemeProperties } from "entities/AppTheming";
|
||||||
|
|
||||||
export default function Preview() {
|
export default function Preview() {
|
||||||
const { key, model, srcDoc, theme, updateDebuggerLogs, updateModel } =
|
const {
|
||||||
useContext(CustomWidgetBuilderContext);
|
key,
|
||||||
|
model,
|
||||||
|
srcDoc,
|
||||||
|
theme,
|
||||||
|
updateDebuggerLogs,
|
||||||
|
updateModel,
|
||||||
|
widgetId,
|
||||||
|
} = useContext(CustomWidgetBuilderContext);
|
||||||
|
|
||||||
const [dimensions, setDimensions] = useState({
|
const [dimensions, setDimensions] = useState({
|
||||||
width: 300,
|
width: 300,
|
||||||
|
|
@ -100,6 +107,7 @@ export default function Preview() {
|
||||||
args: [{ message }, { message: data }],
|
args: [{ message }, { message: data }],
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
|
widgetId={widgetId || ""}
|
||||||
width={dimensions.width}
|
width={dimensions.width}
|
||||||
/>
|
/>
|
||||||
<Debugger />
|
<Debugger />
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ export const LOCAL_STORAGE_KEYS_SELECTED_LAYOUT =
|
||||||
|
|
||||||
export const DEFAULT_CONTEXT_VALUE = {
|
export const DEFAULT_CONTEXT_VALUE = {
|
||||||
name: "",
|
name: "",
|
||||||
|
widgetId: "",
|
||||||
srcDoc: {
|
srcDoc: {
|
||||||
html: "<div>Hello World</div>",
|
html: "<div>Hello World</div>",
|
||||||
js: "function test() {console.log('Hello World');}",
|
js: "function test() {console.log('Hello World');}",
|
||||||
|
|
@ -55,3 +56,6 @@ export const DEFAULT_CONTEXT_VALUE = {
|
||||||
|
|
||||||
export const CUSTOM_WIDGET_DOC_URL =
|
export const CUSTOM_WIDGET_DOC_URL =
|
||||||
"https://docs.appsmith.com/reference/widgets/custom";
|
"https://docs.appsmith.com/reference/widgets/custom";
|
||||||
|
|
||||||
|
export const CUSTOM_WIDGET_DEFAULT_MODEL_DOC_URL =
|
||||||
|
"https://docs.appsmith.com/reference/widgets/custom#default-model";
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,8 @@ import {
|
||||||
} from "./types";
|
} from "./types";
|
||||||
import { compileSrcDoc } from "./utility";
|
import { compileSrcDoc } from "./utility";
|
||||||
import ConnectionLost from "./connectionLost";
|
import ConnectionLost from "./connectionLost";
|
||||||
|
import Helmet from "react-helmet";
|
||||||
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
export const CustomWidgetBuilderContext = React.createContext<
|
export const CustomWidgetBuilderContext = React.createContext<
|
||||||
Partial<CustomWidgetBuilderContextType>
|
Partial<CustomWidgetBuilderContextType>
|
||||||
|
|
@ -56,7 +58,7 @@ export default function CustomWidgetBuilder() {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (contextValue.lastSaved) {
|
if (contextValue.lastSaved) {
|
||||||
window.opener.postMessage(
|
window.opener?.postMessage(
|
||||||
{
|
{
|
||||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.UPDATE_SRCDOC,
|
type: CUSTOM_WIDGET_BUILDER_EVENTS.UPDATE_SRCDOC,
|
||||||
srcDoc: result.code,
|
srcDoc: result.code,
|
||||||
|
|
@ -106,7 +108,7 @@ export default function CustomWidgetBuilder() {
|
||||||
setSelectedLayout(layout);
|
setSelectedLayout(layout);
|
||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
window.opener.focus();
|
window.opener?.focus();
|
||||||
window.close();
|
window.close();
|
||||||
},
|
},
|
||||||
bulkUpdate: (uncompiledSrcDoc: SrcDoc) => {
|
bulkUpdate: (uncompiledSrcDoc: SrcDoc) => {
|
||||||
|
|
@ -129,6 +131,11 @@ export default function CustomWidgetBuilder() {
|
||||||
lastSaved: Date.now(),
|
lastSaved: Date.now(),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_SRCDOC_UPDATE", {
|
||||||
|
widgetId: contextValue.widgetId,
|
||||||
|
srcDocFile: editor,
|
||||||
|
});
|
||||||
},
|
},
|
||||||
updateModel: (model: Record<string, unknown>) => {
|
updateModel: (model: Record<string, unknown>) => {
|
||||||
setContextValue((prev) => {
|
setContextValue((prev) => {
|
||||||
|
|
@ -187,6 +194,7 @@ export default function CustomWidgetBuilder() {
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
name: event.data.name,
|
name: event.data.name,
|
||||||
|
widgetId: event.data.widgetId,
|
||||||
srcDoc: event.data.srcDoc,
|
srcDoc: event.data.srcDoc,
|
||||||
uncompiledSrcDoc: event.data.uncompiledSrcDoc,
|
uncompiledSrcDoc: event.data.uncompiledSrcDoc,
|
||||||
initialSrcDoc: event.data.uncompiledSrcDoc,
|
initialSrcDoc: event.data.uncompiledSrcDoc,
|
||||||
|
|
@ -222,13 +230,21 @@ export default function CustomWidgetBuilder() {
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
showConnectionLostMessage: false,
|
showConnectionLostMessage: false,
|
||||||
|
name: event.data.name,
|
||||||
|
widgetId: event.data.widgetId,
|
||||||
|
srcDoc: event.data.srcDoc,
|
||||||
|
uncompiledSrcDoc: event.data.uncompiledSrcDoc,
|
||||||
|
initialSrcDoc: event.data.uncompiledSrcDoc,
|
||||||
|
model: event.data.model,
|
||||||
|
events: event.data.events,
|
||||||
|
theme: event.data.theme,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.opener.postMessage(
|
window.opener?.postMessage(
|
||||||
{
|
{
|
||||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.READY,
|
type: CUSTOM_WIDGET_BUILDER_EVENTS.READY,
|
||||||
},
|
},
|
||||||
|
|
@ -236,7 +252,7 @@ export default function CustomWidgetBuilder() {
|
||||||
);
|
);
|
||||||
|
|
||||||
window.addEventListener("beforeunload", () => {
|
window.addEventListener("beforeunload", () => {
|
||||||
window.opener.postMessage(
|
window.opener?.postMessage(
|
||||||
{
|
{
|
||||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.DISCONNECTED,
|
type: CUSTOM_WIDGET_BUILDER_EVENTS.DISCONNECTED,
|
||||||
},
|
},
|
||||||
|
|
@ -252,6 +268,10 @@ export default function CustomWidgetBuilder() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CustomWidgetBuilderContext.Provider value={context}>
|
<CustomWidgetBuilderContext.Provider value={context}>
|
||||||
|
<Helmet>
|
||||||
|
<meta charSet="utf-8" />
|
||||||
|
<title>{`${contextValue.name} | Builder | Appsmith`}</title>
|
||||||
|
</Helmet>
|
||||||
<Header />
|
<Header />
|
||||||
{loading ? (
|
{loading ? (
|
||||||
<Spinner className={styles.loader} size="lg" />
|
<Spinner className={styles.loader} size="lg" />
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ export interface SrcDoc {
|
||||||
export interface CustomWidgetBuilderContextValueType {
|
export interface CustomWidgetBuilderContextValueType {
|
||||||
//Custom widget name
|
//Custom widget name
|
||||||
name: string;
|
name: string;
|
||||||
|
widgetId: string;
|
||||||
|
|
||||||
isReferenceOpen: boolean;
|
isReferenceOpen: boolean;
|
||||||
selectedLayout: string;
|
selectedLayout: string;
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,11 @@ const ResetIcon = importSvg(
|
||||||
const StyledDeviated = styled.div`
|
const StyledDeviated = styled.div`
|
||||||
background-color: var(--ads-v2-color-bg-brand);
|
background-color: var(--ads-v2-color-bg-brand);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const LabelContainer = styled.div<{ hasEditIcon: boolean }>`
|
||||||
|
${(props) => props.hasEditIcon && "max-width: calc(100% - 110px);"}
|
||||||
|
`;
|
||||||
|
|
||||||
type Props = PropertyPaneControlConfig & {
|
type Props = PropertyPaneControlConfig & {
|
||||||
panel: IPanelProps;
|
panel: IPanelProps;
|
||||||
theme: EditorTheme;
|
theme: EditorTheme;
|
||||||
|
|
@ -646,6 +651,10 @@ const PropertyControl = memo((props: Props) => {
|
||||||
onDeleteProperties([props.propertyName]);
|
onDeleteProperties([props.propertyName]);
|
||||||
}
|
}
|
||||||
resetEditing();
|
resetEditing();
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_EDIT_EVENT_SAVE_CLICKED", {
|
||||||
|
widgetId: widgetProperties.widgetId,
|
||||||
|
});
|
||||||
}, [
|
}, [
|
||||||
props,
|
props,
|
||||||
onBatchUpdateProperties,
|
onBatchUpdateProperties,
|
||||||
|
|
@ -657,6 +666,10 @@ const PropertyControl = memo((props: Props) => {
|
||||||
const resetEditing = useCallback(() => {
|
const resetEditing = useCallback(() => {
|
||||||
setEditedName(props.propertyName);
|
setEditedName(props.propertyName);
|
||||||
setIsRenaming(false);
|
setIsRenaming(false);
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent("CUSTOM_WIDGET_EDIT_EVENT_CANCEL_CLICKED", {
|
||||||
|
widgetId: widgetProperties.widgetId,
|
||||||
|
});
|
||||||
}, [props.propertyName]);
|
}, [props.propertyName]);
|
||||||
|
|
||||||
const { propertyName } = props;
|
const { propertyName } = props;
|
||||||
|
|
@ -913,8 +926,15 @@ const PropertyControl = memo((props: Props) => {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className={clsx("flex items-center justify-right gap-1")}>
|
<LabelContainer
|
||||||
|
className={clsx("flex items-center justify-right gap-1")}
|
||||||
|
hasEditIcon={
|
||||||
|
!!config.controlConfig?.allowEdit ||
|
||||||
|
!!config.controlConfig?.allowDelete
|
||||||
|
}
|
||||||
|
>
|
||||||
<PropertyHelpLabel
|
<PropertyHelpLabel
|
||||||
|
className="w-full"
|
||||||
label={label}
|
label={label}
|
||||||
theme={props.theme}
|
theme={props.theme}
|
||||||
tooltip={helpText}
|
tooltip={helpText}
|
||||||
|
|
@ -964,7 +984,7 @@ const PropertyControl = memo((props: Props) => {
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</LabelContainer>
|
||||||
<div className={clsx("flex items-center justify-right")}>
|
<div className={clsx("flex items-center justify-right")}>
|
||||||
{config.controlConfig?.allowEdit && (
|
{config.controlConfig?.allowEdit && (
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -975,7 +995,15 @@ const PropertyControl = memo((props: Props) => {
|
||||||
)}
|
)}
|
||||||
isIconButton
|
isIconButton
|
||||||
kind="tertiary"
|
kind="tertiary"
|
||||||
onClick={() => setIsRenaming(true)}
|
onClick={() => {
|
||||||
|
setIsRenaming(true);
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_EDIT_EVENT_CLICKED",
|
||||||
|
{
|
||||||
|
widgetId: widgetProperties.widgetId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}}
|
||||||
size="small"
|
size="small"
|
||||||
startIcon="pencil-line"
|
startIcon="pencil-line"
|
||||||
/>
|
/>
|
||||||
|
|
@ -1000,6 +1028,13 @@ const PropertyControl = memo((props: Props) => {
|
||||||
onBatchUpdateProperties(updates);
|
onBatchUpdateProperties(updates);
|
||||||
}
|
}
|
||||||
onDeleteProperties([config.propertyName]);
|
onDeleteProperties([config.propertyName]);
|
||||||
|
|
||||||
|
AnalyticsUtil.logEvent(
|
||||||
|
"CUSTOM_WIDGET_DELETE_EVENT_CLICKED",
|
||||||
|
{
|
||||||
|
widgetId: widgetProperties.widgetId,
|
||||||
|
},
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
size="small"
|
size="small"
|
||||||
startIcon="trash"
|
startIcon="trash"
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,9 @@ function PropertyHelpLabel(props: Props) {
|
||||||
content={props.tooltip || ""}
|
content={props.tooltip || ""}
|
||||||
isDisabled={!toolTipDefined}
|
isDisabled={!toolTipDefined}
|
||||||
>
|
>
|
||||||
<div onClick={props.onClick}>
|
<div className="w-full" onClick={props.onClick}>
|
||||||
<Label
|
<Label
|
||||||
className={`t--property-control-label`}
|
className={`t--property-control-label w-full block text-ellipsis overflow-hidden`}
|
||||||
style={{
|
style={{
|
||||||
cursor: toolTipDefined ? "help" : "default",
|
cursor: toolTipDefined ? "help" : "default",
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -389,6 +389,20 @@ function getDynamicTriggerPathListUpdate(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DYNAMIC_BINDING_IGNORED_LIST = [
|
||||||
|
/* Table widget */
|
||||||
|
"primaryColumns",
|
||||||
|
"derivedColumns",
|
||||||
|
|
||||||
|
/* custom widget */
|
||||||
|
"srcDoc.html",
|
||||||
|
"srcDoc.css",
|
||||||
|
"srcDoc.js",
|
||||||
|
"uncompiledSrcDoc.html",
|
||||||
|
"uncompiledSrcDoc.css",
|
||||||
|
"uncompiledSrcDoc.js",
|
||||||
|
];
|
||||||
|
|
||||||
function getDynamicBindingPathListUpdate(
|
function getDynamicBindingPathListUpdate(
|
||||||
widget: WidgetProps,
|
widget: WidgetProps,
|
||||||
propertyPath: string,
|
propertyPath: string,
|
||||||
|
|
@ -400,9 +414,12 @@ function getDynamicBindingPathListUpdate(
|
||||||
stringProp = JSON.stringify(propertyValue);
|
stringProp = JSON.stringify(propertyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO(abhinav): This is not appropriate from the platform's archtecture's point of view.
|
/*
|
||||||
|
* TODO(Balaji Soundararajan): This is not appropriate from the platform's archtecture's point of view.
|
||||||
|
* This setting should come from widget configuration
|
||||||
|
*/
|
||||||
// Figure out a holistic solutions where we donot have to stringify above.
|
// Figure out a holistic solutions where we donot have to stringify above.
|
||||||
if (propertyPath === "primaryColumns" || propertyPath === "derivedColumns") {
|
if (DYNAMIC_BINDING_IGNORED_LIST.includes(propertyPath)) {
|
||||||
return {
|
return {
|
||||||
propertyPath,
|
propertyPath,
|
||||||
effect: DynamicPathUpdateEffectEnum.NOOP,
|
effect: DynamicPathUpdateEffectEnum.NOOP,
|
||||||
|
|
|
||||||
|
|
@ -86,11 +86,13 @@ export default class CustomWidgetBuilderService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static closeConnection(widgetId: string) {
|
static closeConnection(widgetId: string, skipClosing?: boolean) {
|
||||||
if (this.builderWindowConnections.has(widgetId)) {
|
if (this.builderWindowConnections.has(widgetId)) {
|
||||||
const connection = this.builderWindowConnections.get(widgetId);
|
if (!skipClosing) {
|
||||||
|
const connection = this.builderWindowConnections.get(widgetId);
|
||||||
|
|
||||||
connection?.window?.close();
|
connection?.window?.close();
|
||||||
|
}
|
||||||
|
|
||||||
this.builderWindowConnections.delete(widgetId);
|
this.builderWindowConnections.delete(widgetId);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -291,8 +291,7 @@ export class ContainerWidget extends BaseWidget<
|
||||||
{
|
{
|
||||||
propertyName: "borderRadius",
|
propertyName: "borderRadius",
|
||||||
label: "Border radius",
|
label: "Border radius",
|
||||||
helpText:
|
helpText: "Rounds the corners of the widgets's outer border edge",
|
||||||
"Rounds the corners of the icon button's outer border edge",
|
|
||||||
controlType: "BORDER_RADIUS_OPTIONS",
|
controlType: "BORDER_RADIUS_OPTIONS",
|
||||||
isJSConvertible: true,
|
isJSConvertible: true,
|
||||||
isBindProperty: true,
|
isBindProperty: true,
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,22 @@ export const CUSTOM_WIDGET_LOAD_EVENTS = {
|
||||||
export const getAppsmithScriptSchema = (model: Record<string, unknown>) => ({
|
export const getAppsmithScriptSchema = (model: Record<string, unknown>) => ({
|
||||||
appsmith: {
|
appsmith: {
|
||||||
mode: "",
|
mode: "",
|
||||||
onUiChange: Function,
|
|
||||||
onModelChange: Function,
|
|
||||||
updateModel: Function,
|
|
||||||
triggerEvent: Function,
|
|
||||||
model: model,
|
model: model,
|
||||||
ui: {
|
ui: {
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 2,
|
height: 2,
|
||||||
},
|
},
|
||||||
|
theme: {
|
||||||
|
primaryColor: "",
|
||||||
|
backgroundColor: "",
|
||||||
|
borderRadius: "",
|
||||||
|
boxShadow: "",
|
||||||
|
},
|
||||||
|
onUiChange: Function,
|
||||||
|
onModelChange: Function,
|
||||||
|
onThemeChange: Function,
|
||||||
|
updateModel: Function,
|
||||||
|
triggerEvent: Function,
|
||||||
onReady: Function,
|
onReady: Function,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,15 @@ import appsmithConsole from "!!raw-loader!./appsmithConsole.js";
|
||||||
import css from "!!raw-loader!./reset.css";
|
import css from "!!raw-loader!./reset.css";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import type { AppThemeProperties } from "entities/AppTheming";
|
import type { AppThemeProperties } from "entities/AppTheming";
|
||||||
|
import WidgetStyleContainer from "components/designSystems/appsmith/WidgetStyleContainer";
|
||||||
|
import type { BoxShadow } from "components/designSystems/appsmith/WidgetStyleContainer";
|
||||||
|
import type { Color } from "constants/Colors";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import type { AppState } from "@appsmith/reducers";
|
||||||
|
import { combinedPreviewModeSelector } from "selectors/editorSelectors";
|
||||||
|
import { getAppMode } from "@appsmith/selectors/applicationSelectors";
|
||||||
|
import { APP_MODE } from "entities/App";
|
||||||
|
import { getWidgetPropsForPropertyPane } from "selectors/propertyPaneSelectors";
|
||||||
|
|
||||||
const StyledIframe = styled.iframe<{ width: number; height: number }>`
|
const StyledIframe = styled.iframe<{ width: number; height: number }>`
|
||||||
width: ${(props) => props.width - 8}px;
|
width: ${(props) => props.width - 8}px;
|
||||||
|
|
@ -191,16 +200,26 @@ function CustomComponent(props: CustomComponentProps) {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
{props.needsOverlay && <OverlayDiv data-testid="iframe-overlay" />}
|
{props.needsOverlay && <OverlayDiv data-testid="iframe-overlay" />}
|
||||||
<StyledIframe
|
<WidgetStyleContainer
|
||||||
height={props.height}
|
backgroundColor={props.backgroundColor}
|
||||||
onLoad={() => {
|
borderColor={props.borderColor}
|
||||||
setLoading(false);
|
borderRadius={props.borderRadius}
|
||||||
}}
|
borderWidth={props.borderWidth}
|
||||||
ref={iframe}
|
boxShadow={props.boxShadow}
|
||||||
sandbox="allow-scripts allow-downloads"
|
widgetId={props.widgetId}
|
||||||
srcDoc={srcDoc}
|
>
|
||||||
width={props.width}
|
<StyledIframe
|
||||||
/>
|
height={props.height}
|
||||||
|
loading="lazy"
|
||||||
|
onLoad={() => {
|
||||||
|
setLoading(false);
|
||||||
|
}}
|
||||||
|
ref={iframe}
|
||||||
|
sandbox="allow-scripts allow-downloads"
|
||||||
|
srcDoc={srcDoc}
|
||||||
|
width={props.width}
|
||||||
|
/>
|
||||||
|
</WidgetStyleContainer>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -221,6 +240,30 @@ export interface CustomComponentProps {
|
||||||
onConsole?: (type: string, message: string) => void;
|
onConsole?: (type: string, message: string) => void;
|
||||||
renderMode: "EDITOR" | "DEPLOYED" | "BUILDER";
|
renderMode: "EDITOR" | "DEPLOYED" | "BUILDER";
|
||||||
theme: AppThemeProperties;
|
theme: AppThemeProperties;
|
||||||
|
borderColor?: Color;
|
||||||
|
backgroundColor?: Color;
|
||||||
|
borderWidth?: number;
|
||||||
|
borderRadius?: number;
|
||||||
|
boxShadow?: BoxShadow;
|
||||||
|
widgetId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default CustomComponent;
|
/**
|
||||||
|
* TODO: Balaji soundararajan - to refactor code to move out selected widget details to platform
|
||||||
|
*/
|
||||||
|
export const mapStateToProps = (
|
||||||
|
state: AppState,
|
||||||
|
ownProps: CustomComponentProps,
|
||||||
|
) => {
|
||||||
|
const isPreviewMode = combinedPreviewModeSelector(state);
|
||||||
|
const appMode = getAppMode(state);
|
||||||
|
|
||||||
|
return {
|
||||||
|
needsOverlay:
|
||||||
|
appMode == APP_MODE.EDIT &&
|
||||||
|
!isPreviewMode &&
|
||||||
|
ownProps.widgetId !== getWidgetPropsForPropertyPane(state)?.widgetId,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(CustomComponent);
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ export default {
|
||||||
height: calc(var(--appsmith-ui-height) * 1px);
|
height: calc(var(--appsmith-ui-height) * 1px);
|
||||||
width: calc(var(--appsmith-ui-width) * 1px);
|
width: calc(var(--appsmith-ui-width) * 1px);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: var(--appsmith-theme-borderRadius);
|
border-radius: 0px;
|
||||||
box-shadow: var(--appsmith-theme-boxShadow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip-container {
|
.tip-container {
|
||||||
|
|
@ -37,13 +36,14 @@ export default {
|
||||||
|
|
||||||
.button-container button {
|
.button-container button {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
|
border-radius: var(--appsmith-theme-borderRadius) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container button.primary {
|
.button-container button.primary {
|
||||||
background: var(--appsmith-theme-primaryColor) !important;
|
background: var(--appsmith-theme-primaryColor) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container button.reset {
|
.button-container button.reset:not([disabled]) {
|
||||||
color: var(--appsmith-theme-primaryColor) !important;
|
color: var(--appsmith-theme-primaryColor) !important;
|
||||||
border-color: var(--appsmith-theme-primaryColor) !important;
|
border-color: var(--appsmith-theme-primaryColor) !important;
|
||||||
}`,
|
}`,
|
||||||
|
|
@ -75,7 +75,7 @@ function App() {
|
||||||
</div>
|
</div>
|
||||||
<div className="button-container">
|
<div className="button-container">
|
||||||
<Button className="primary" onClick={handleNext} type="primary">Next Tip</Button>
|
<Button className="primary" onClick={handleNext} type="primary">Next Tip</Button>
|
||||||
<Button className="reset" onClick={handleReset}>Reset</Button>
|
<Button className="reset" disabled={currentIndex === 0} onClick={handleReset}>Reset</Button>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
@ -93,8 +93,7 @@ appsmith.onReady(() => {
|
||||||
height: calc(var(--appsmith-ui-height) * 1px);
|
height: calc(var(--appsmith-ui-height) * 1px);
|
||||||
width: calc(var(--appsmith-ui-width) * 1px);
|
width: calc(var(--appsmith-ui-width) * 1px);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border-radius: var(--appsmith-theme-borderRadius);
|
border-radius: 0px;
|
||||||
box-shadow: var(--appsmith-theme-boxShadow);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.tip-container {
|
.tip-container {
|
||||||
|
|
@ -123,13 +122,14 @@ appsmith.onReady(() => {
|
||||||
|
|
||||||
.button-container button {
|
.button-container button {
|
||||||
margin: 0 10px;
|
margin: 0 10px;
|
||||||
|
border-radius: var(--appsmith-theme-borderRadius) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container button.primary {
|
.button-container button.primary {
|
||||||
background: var(--appsmith-theme-primaryColor) !important;
|
background: var(--appsmith-theme-primaryColor) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button-container button.reset {
|
.button-container button.reset:not([disabled]) {
|
||||||
color: var(--appsmith-theme-primaryColor) !important;
|
color: var(--appsmith-theme-primaryColor) !important;
|
||||||
border-color: var(--appsmith-theme-primaryColor) !important;
|
border-color: var(--appsmith-theme-primaryColor) !important;
|
||||||
}`,
|
}`,
|
||||||
|
|
@ -161,6 +161,7 @@ function App() {
|
||||||
type: "primary"
|
type: "primary"
|
||||||
}, "Next Tip"), /*#__PURE__*/React.createElement(Button, {
|
}, "Next Tip"), /*#__PURE__*/React.createElement(Button, {
|
||||||
className: "reset",
|
className: "reset",
|
||||||
|
disabled: currentIndex === 0,
|
||||||
onClick: handleReset
|
onClick: handleReset
|
||||||
}, "Reset")));
|
}, "Reset")));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,13 @@ import BaseWidget from "widgets/BaseWidget";
|
||||||
import CustomComponent from "../component";
|
import CustomComponent from "../component";
|
||||||
|
|
||||||
import IconSVG from "../icon.svg";
|
import IconSVG from "../icon.svg";
|
||||||
import { RenderModes, WIDGET_TAGS } from "constants/WidgetConstants";
|
import { WIDGET_TAGS } from "constants/WidgetConstants";
|
||||||
import { ValidationTypes } from "constants/WidgetValidation";
|
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 { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
|
||||||
import type { AutocompletionDefinitions } from "WidgetProvider/constants";
|
import type { AutocompletionDefinitions } from "WidgetProvider/constants";
|
||||||
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
import { FEATURE_FLAG } from "@appsmith/entities/FeatureFlag";
|
||||||
|
|
@ -19,9 +23,14 @@ import { DEFAULT_MODEL } from "../constants";
|
||||||
import defaultApp from "./defaultApp";
|
import defaultApp from "./defaultApp";
|
||||||
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
import type { ExtraDef } from "utils/autocomplete/defCreatorUtils";
|
||||||
import { generateTypeDef } 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 { Link } from "design-system";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||||
|
import { Colors } from "constants/Colors";
|
||||||
|
|
||||||
const StyledLink = styled(Link)`
|
const StyledLink = styled(Link)`
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
|
@ -52,7 +61,7 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
||||||
return {
|
return {
|
||||||
widgetName: "Custom",
|
widgetName: "Custom",
|
||||||
rows: 30,
|
rows: 30,
|
||||||
columns: 20,
|
columns: 23,
|
||||||
version: 1,
|
version: 1,
|
||||||
onResetClick: "{{showAlert('Successfully reset!!', '');}}",
|
onResetClick: "{{showAlert('Successfully reset!!', '');}}",
|
||||||
events: ["onResetClick"],
|
events: ["onResetClick"],
|
||||||
|
|
@ -62,6 +71,9 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
||||||
uncompiledSrcDoc: defaultApp.uncompiledSrcDoc,
|
uncompiledSrcDoc: defaultApp.uncompiledSrcDoc,
|
||||||
theme: "{{appsmith.theme}}",
|
theme: "{{appsmith.theme}}",
|
||||||
dynamicBindingPathList: [{ key: "theme" }],
|
dynamicBindingPathList: [{ key: "theme" }],
|
||||||
|
borderColor: Colors.GREY_5,
|
||||||
|
borderWidth: "1",
|
||||||
|
backgroundColor: "#FFFFFF",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -83,6 +95,13 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getStylesheetConfig(): Stylesheet {
|
||||||
|
return {
|
||||||
|
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||||
|
boxShadow: "{{appsmith.theme.boxShadow.appBoxShadow}}",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
static getPropertyPaneContentConfig() {
|
static getPropertyPaneContentConfig() {
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
|
|
@ -126,7 +145,7 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
||||||
kind="secondary"
|
kind="secondary"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
to={CUSTOM_WIDGET_DOC_URL}
|
to={CUSTOM_WIDGET_DEFAULT_MODEL_DOC_URL}
|
||||||
>
|
>
|
||||||
Read more
|
Read more
|
||||||
</StyledLink>
|
</StyledLink>
|
||||||
|
|
@ -190,6 +209,7 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
dependencies: ["events"],
|
dependencies: ["events"],
|
||||||
|
helpText: "when the event is triggered from custom widget",
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -217,7 +237,71 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
||||||
}
|
}
|
||||||
|
|
||||||
static getPropertyPaneStyleConfig() {
|
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 {
|
static getDerivedPropertiesMap(): DerivedPropertiesMap {
|
||||||
|
|
@ -270,17 +354,19 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
||||||
getWidgetView() {
|
getWidgetView() {
|
||||||
return (
|
return (
|
||||||
<CustomComponent
|
<CustomComponent
|
||||||
|
backgroundColor={this.props.backgroundColor}
|
||||||
|
borderColor={this.props.borderColor}
|
||||||
|
borderRadius={this.props.borderRadius}
|
||||||
|
borderWidth={this.props.borderWidth}
|
||||||
|
boxShadow={this.props.boxShadow}
|
||||||
execute={this.execute}
|
execute={this.execute}
|
||||||
height={this.props.componentHeight}
|
height={this.props.componentHeight}
|
||||||
model={this.props.model || {}}
|
model={this.props.model || {}}
|
||||||
needsOverlay={
|
|
||||||
this.props.renderMode === RenderModes.CANVAS &&
|
|
||||||
!this.props.isWidgetSelected
|
|
||||||
}
|
|
||||||
renderMode={this.getRenderMode()}
|
renderMode={this.getRenderMode()}
|
||||||
srcDoc={this.props.srcDoc}
|
srcDoc={this.props.srcDoc}
|
||||||
theme={this.props.theme}
|
theme={this.props.theme}
|
||||||
update={this.update}
|
update={this.update}
|
||||||
|
widgetId={this.props.widgetId}
|
||||||
width={this.props.componentWidth}
|
width={this.props.componentWidth}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user