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 () {
|
||||
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", () => {
|
||||
|
|
|
|||
|
|
@ -2375,7 +2375,7 @@ export const CUSTOM_WIDGET_FEATURE = {
|
|||
split: () => "Splits",
|
||||
},
|
||||
referrences: {
|
||||
title: () => "Referrences",
|
||||
title: () => "References",
|
||||
tooltip: {
|
||||
open: () => "Open references",
|
||||
close: () => "Close references",
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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<
|
|||
) : (
|
||||
<Button
|
||||
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"
|
||||
startIcon="plus"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import {
|
|||
} from "@appsmith/constants/messages";
|
||||
import CustomWidgetBuilderService from "utils/CustomWidgetBuilderService";
|
||||
import styled from "styled-components";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
interface ButtonControlState {
|
||||
isSourceEditorOpen: boolean;
|
||||
|
|
@ -24,7 +25,32 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
|||
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 = () => {
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_EDIT_SOURCE_CLICKED", {
|
||||
widgetId: this.props.widgetProperties.widgetId,
|
||||
});
|
||||
|
||||
if (
|
||||
CustomWidgetBuilderService.isConnected(
|
||||
this.props.widgetProperties.widgetId,
|
||||
|
|
@ -40,22 +66,7 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
|||
onMessage(CUSTOM_WIDGET_BUILDER_EVENTS.READY, () => {
|
||||
postMessage({
|
||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.READY_ACK,
|
||||
name: this.props.widgetProperties.widgetName,
|
||||
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,
|
||||
...this.getPayload(),
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -74,6 +85,7 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
|||
onMessage(CUSTOM_WIDGET_BUILDER_EVENTS.DISCONNECTED, () => {
|
||||
CustomWidgetBuilderService.closeConnection(
|
||||
this.props.widgetProperties.widgetId,
|
||||
true,
|
||||
);
|
||||
|
||||
this.setState({
|
||||
|
|
@ -105,6 +117,7 @@ class ButtonControl extends BaseControl<ControlProps, ButtonControlState> {
|
|||
this.props.widgetProperties.widgetId,
|
||||
)?.postMessage({
|
||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.RESUME,
|
||||
...this.getPayload(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import {
|
|||
CUSTOM_WIDGET_FEATURE,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
const StyledButton = styled(Button)`
|
||||
height: 32px !important;
|
||||
|
|
@ -70,13 +71,14 @@ function ConfirmationModal(props: {
|
|||
}
|
||||
|
||||
export function CodeTemplates() {
|
||||
const { bulkUpdate, initialSrcDoc, lastSaved } = useContext(
|
||||
const { bulkUpdate, initialSrcDoc, lastSaved, widgetId } = useContext(
|
||||
CustomWidgetBuilderContext,
|
||||
);
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const [selectedTemplate, setSelectedTemplate] = useState<SrcDoc | null>(null);
|
||||
const [selectedTemplateName, setSelectedTemplateName] = useState("");
|
||||
|
||||
return (
|
||||
<div className={styles.templateMenu}>
|
||||
|
|
@ -85,9 +87,13 @@ export function CodeTemplates() {
|
|||
<StyledButton
|
||||
className="t--custom-widget-template-trigger"
|
||||
kind="secondary"
|
||||
onClick={() => {
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_TEMPLATE_OPENED", {
|
||||
widgetId: widgetId,
|
||||
});
|
||||
}}
|
||||
size="sm"
|
||||
startIcon="query"
|
||||
style={{}}
|
||||
>
|
||||
{createMessage(CUSTOM_WIDGET_FEATURE.template.buttonCTA)}
|
||||
</StyledButton>
|
||||
|
|
@ -98,7 +104,17 @@ export function CodeTemplates() {
|
|||
<MenuItem
|
||||
onClick={() => {
|
||||
setSelectedTemplate(initialSrcDoc);
|
||||
setSelectedTemplateName(
|
||||
CUSTOM_WIDGET_FEATURE.template.revert,
|
||||
);
|
||||
setOpen(true);
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT",
|
||||
{
|
||||
widgetId: widgetId,
|
||||
templateName: CUSTOM_WIDGET_FEATURE.template.revert,
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{createMessage(CUSTOM_WIDGET_FEATURE.template.revert)}
|
||||
|
|
@ -111,7 +127,15 @@ export function CodeTemplates() {
|
|||
key={template.key}
|
||||
onClick={() => {
|
||||
setSelectedTemplate(template.uncompiledSrcDoc);
|
||||
setSelectedTemplateName(template.key);
|
||||
setOpen(true);
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT",
|
||||
{
|
||||
widgetId: widgetId,
|
||||
templateName: template.key,
|
||||
},
|
||||
);
|
||||
}}
|
||||
>
|
||||
{template.key}
|
||||
|
|
@ -122,18 +146,42 @@ export function CodeTemplates() {
|
|||
<ConfirmationModal
|
||||
onCancel={() => {
|
||||
setSelectedTemplate(null);
|
||||
setSelectedTemplateName("");
|
||||
setOpen(false);
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CANCELED",
|
||||
{
|
||||
widgetId: widgetId,
|
||||
templateName: selectedTemplateName,
|
||||
},
|
||||
);
|
||||
}}
|
||||
onOpenChange={(flag: boolean) => {
|
||||
if (!flag) {
|
||||
setSelectedTemplate(null);
|
||||
setSelectedTemplateName("");
|
||||
setOpen(false);
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CANCELED",
|
||||
{
|
||||
widgetId: widgetId,
|
||||
templateName: selectedTemplateName,
|
||||
},
|
||||
);
|
||||
}
|
||||
}}
|
||||
onReplace={() => {
|
||||
selectedTemplate && bulkUpdate?.(selectedTemplate);
|
||||
setSelectedTemplate(null);
|
||||
setSelectedTemplateName("");
|
||||
setOpen(false);
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_BUILDER_TEMPLATE_SELECT_CONFIRMED",
|
||||
{
|
||||
widgetId: widgetId,
|
||||
templateName: selectedTemplateName,
|
||||
},
|
||||
);
|
||||
}}
|
||||
open={open}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
CUSTOM_WIDGET_FEATURE,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
const StyledSegmentedControl = styled(SegmentedControl)`
|
||||
& .ads-v2-icon {
|
||||
|
|
@ -15,10 +16,17 @@ const StyledSegmentedControl = styled(SegmentedControl)`
|
|||
`;
|
||||
|
||||
export default function LayoutControls() {
|
||||
const context = useContext(CustomWidgetBuilderContext);
|
||||
const { selectedLayout, selectLayout, widgetId } = useContext(
|
||||
CustomWidgetBuilderContext,
|
||||
);
|
||||
|
||||
const onChange = (value: string) => {
|
||||
context.selectLayout?.(value);
|
||||
selectLayout?.(value);
|
||||
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_LAYOUT_CHANGED", {
|
||||
widgetId: widgetId,
|
||||
layoutName: value,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
@ -37,7 +45,7 @@ export default function LayoutControls() {
|
|||
value: "tabs",
|
||||
},
|
||||
]}
|
||||
value={context.selectedLayout}
|
||||
value={selectedLayout}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -6,14 +6,23 @@ import {
|
|||
CUSTOM_WIDGET_FEATURE,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
export default function ReferenceTrigger() {
|
||||
const { isReferenceOpen, toggleReference } = useContext(
|
||||
const { isReferenceOpen, toggleReference, widgetId } = useContext(
|
||||
CustomWidgetBuilderContext,
|
||||
);
|
||||
|
||||
const onClick = () => {
|
||||
toggleReference?.();
|
||||
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_BUILDER_REFERENCE_VISIBILITY_CHANGED",
|
||||
{
|
||||
widgetId: widgetId,
|
||||
visible: !isReferenceOpen,
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
CUSTOM_WIDGET_FEATURE,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
const StyledLazyCodeEditorWrapper = styled.div`
|
||||
.CodeMirror-line.CodeMirror-line {
|
||||
|
|
@ -31,11 +32,16 @@ const StyledLazyCodeEditorWrapper = styled.div`
|
|||
`;
|
||||
|
||||
export default function Events() {
|
||||
const { events } = useContext(CustomWidgetBuilderContext);
|
||||
const { events, widgetId } = useContext(CustomWidgetBuilderContext);
|
||||
|
||||
const [openState, setOpenState] = useState<Record<string, boolean>>({});
|
||||
|
||||
const toggleOpen = useCallback((event: string) => {
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_REFERENCE_EVENT_OPENED", {
|
||||
widgetId: widgetId,
|
||||
eventName: event,
|
||||
});
|
||||
|
||||
setOpenState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
|
|
|
|||
|
|
@ -63,6 +63,9 @@
|
|||
font-weight: 400;
|
||||
margin-right: 2px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
width: calc(100% - 22px);
|
||||
}
|
||||
|
||||
.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 DebuggerItem from "./debuggerItem";
|
||||
import styles from "./styles.module.css";
|
||||
|
|
@ -11,6 +11,7 @@ import {
|
|||
CUSTOM_WIDGET_FEATURE,
|
||||
createMessage,
|
||||
} from "@appsmith/constants/messages";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
const LOCAL_STORAGE_KEYS_IS_DEBUGGER_OPEN =
|
||||
"custom-widget-builder-context-state-is-debugger-open";
|
||||
|
|
@ -23,7 +24,7 @@ export default function Debugger() {
|
|||
false,
|
||||
);
|
||||
|
||||
const { clearDegbuggerLogs, debuggerLogs } = useContext(
|
||||
const { clearDegbuggerLogs, debuggerLogs, widgetId } = useContext(
|
||||
CustomWidgetBuilderContext,
|
||||
);
|
||||
|
||||
|
|
@ -31,6 +32,17 @@ export default function Debugger() {
|
|||
scrollToRef.current?.scrollIntoView({ behavior: "smooth" });
|
||||
}, [debuggerLogs]);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setOpen(!open);
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_BUILDER_DEBUGGER_VISIBILITY_CHANGED",
|
||||
{
|
||||
widgetId: widgetId,
|
||||
visible: !open,
|
||||
},
|
||||
);
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<div className={styles.debuggerActions}>
|
||||
|
|
@ -43,31 +55,36 @@ export default function Debugger() {
|
|||
debuggerLogs?.filter((d) => d.type === DebuggerLogType.LOG)
|
||||
.length || 0
|
||||
}
|
||||
onClick={() => setOpen(!open)}
|
||||
onClick={() => toggle()}
|
||||
warn={
|
||||
debuggerLogs?.filter((d) => d.type === DebuggerLogType.WARN)
|
||||
.length || 0
|
||||
}
|
||||
/>
|
||||
<Tooltip content="clear console">
|
||||
<Tooltip content="Clear console">
|
||||
<Icon
|
||||
name="forbid-line"
|
||||
onClick={() => clearDegbuggerLogs?.()}
|
||||
onClick={() => {
|
||||
clearDegbuggerLogs?.();
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_DEBUGGER_CLEARED", {
|
||||
widgetId: widgetId,
|
||||
});
|
||||
}}
|
||||
size="md"
|
||||
style={{ cursor: "pointer" }}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Tooltip content={open ? "close console" : "open console"}>
|
||||
<Tooltip content={open ? "Close console" : "Open console"}>
|
||||
<Icon
|
||||
name={open ? "arrow-down-s-line" : "arrow-up-s-line"}
|
||||
onClick={() => setOpen(!open)}
|
||||
onClick={() => toggle()}
|
||||
size="lg"
|
||||
style={{ cursor: "pointer" }}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Tabs value={"Debugger"}>
|
||||
<TabsList className={styles.debuggerTab} onClick={() => setOpen(!open)}>
|
||||
<TabsList className={styles.debuggerTab} onClick={() => toggle()}>
|
||||
<Tab key="Debugger" value="Debugger">
|
||||
{createMessage(CUSTOM_WIDGET_FEATURE.debugger.title)}
|
||||
</Tab>
|
||||
|
|
|
|||
|
|
@ -11,8 +11,15 @@ import {
|
|||
import type { AppThemeProperties } from "entities/AppTheming";
|
||||
|
||||
export default function Preview() {
|
||||
const { key, model, srcDoc, theme, updateDebuggerLogs, updateModel } =
|
||||
useContext(CustomWidgetBuilderContext);
|
||||
const {
|
||||
key,
|
||||
model,
|
||||
srcDoc,
|
||||
theme,
|
||||
updateDebuggerLogs,
|
||||
updateModel,
|
||||
widgetId,
|
||||
} = useContext(CustomWidgetBuilderContext);
|
||||
|
||||
const [dimensions, setDimensions] = useState({
|
||||
width: 300,
|
||||
|
|
@ -100,6 +107,7 @@ export default function Preview() {
|
|||
args: [{ message }, { message: data }],
|
||||
});
|
||||
}}
|
||||
widgetId={widgetId || ""}
|
||||
width={dimensions.width}
|
||||
/>
|
||||
<Debugger />
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ export const LOCAL_STORAGE_KEYS_SELECTED_LAYOUT =
|
|||
|
||||
export const DEFAULT_CONTEXT_VALUE = {
|
||||
name: "",
|
||||
widgetId: "",
|
||||
srcDoc: {
|
||||
html: "<div>Hello World</div>",
|
||||
js: "function test() {console.log('Hello World');}",
|
||||
|
|
@ -55,3 +56,6 @@ export const DEFAULT_CONTEXT_VALUE = {
|
|||
|
||||
export const CUSTOM_WIDGET_DOC_URL =
|
||||
"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";
|
||||
import { compileSrcDoc } from "./utility";
|
||||
import ConnectionLost from "./connectionLost";
|
||||
import Helmet from "react-helmet";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
|
||||
export const CustomWidgetBuilderContext = React.createContext<
|
||||
Partial<CustomWidgetBuilderContextType>
|
||||
|
|
@ -56,7 +58,7 @@ export default function CustomWidgetBuilder() {
|
|||
});
|
||||
|
||||
if (contextValue.lastSaved) {
|
||||
window.opener.postMessage(
|
||||
window.opener?.postMessage(
|
||||
{
|
||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.UPDATE_SRCDOC,
|
||||
srcDoc: result.code,
|
||||
|
|
@ -106,7 +108,7 @@ export default function CustomWidgetBuilder() {
|
|||
setSelectedLayout(layout);
|
||||
},
|
||||
close: () => {
|
||||
window.opener.focus();
|
||||
window.opener?.focus();
|
||||
window.close();
|
||||
},
|
||||
bulkUpdate: (uncompiledSrcDoc: SrcDoc) => {
|
||||
|
|
@ -129,6 +131,11 @@ export default function CustomWidgetBuilder() {
|
|||
lastSaved: Date.now(),
|
||||
};
|
||||
});
|
||||
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_BUILDER_SRCDOC_UPDATE", {
|
||||
widgetId: contextValue.widgetId,
|
||||
srcDocFile: editor,
|
||||
});
|
||||
},
|
||||
updateModel: (model: Record<string, unknown>) => {
|
||||
setContextValue((prev) => {
|
||||
|
|
@ -187,6 +194,7 @@ export default function CustomWidgetBuilder() {
|
|||
return {
|
||||
...prev,
|
||||
name: event.data.name,
|
||||
widgetId: event.data.widgetId,
|
||||
srcDoc: event.data.srcDoc,
|
||||
uncompiledSrcDoc: event.data.uncompiledSrcDoc,
|
||||
initialSrcDoc: event.data.uncompiledSrcDoc,
|
||||
|
|
@ -222,13 +230,21 @@ export default function CustomWidgetBuilder() {
|
|||
return {
|
||||
...prev,
|
||||
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;
|
||||
}
|
||||
});
|
||||
|
||||
window.opener.postMessage(
|
||||
window.opener?.postMessage(
|
||||
{
|
||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.READY,
|
||||
},
|
||||
|
|
@ -236,7 +252,7 @@ export default function CustomWidgetBuilder() {
|
|||
);
|
||||
|
||||
window.addEventListener("beforeunload", () => {
|
||||
window.opener.postMessage(
|
||||
window.opener?.postMessage(
|
||||
{
|
||||
type: CUSTOM_WIDGET_BUILDER_EVENTS.DISCONNECTED,
|
||||
},
|
||||
|
|
@ -252,6 +268,10 @@ export default function CustomWidgetBuilder() {
|
|||
|
||||
return (
|
||||
<CustomWidgetBuilderContext.Provider value={context}>
|
||||
<Helmet>
|
||||
<meta charSet="utf-8" />
|
||||
<title>{`${contextValue.name} | Builder | Appsmith`}</title>
|
||||
</Helmet>
|
||||
<Header />
|
||||
{loading ? (
|
||||
<Spinner className={styles.loader} size="lg" />
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ export interface SrcDoc {
|
|||
export interface CustomWidgetBuilderContextValueType {
|
||||
//Custom widget name
|
||||
name: string;
|
||||
widgetId: string;
|
||||
|
||||
isReferenceOpen: boolean;
|
||||
selectedLayout: string;
|
||||
|
|
|
|||
|
|
@ -70,6 +70,11 @@ const ResetIcon = importSvg(
|
|||
const StyledDeviated = styled.div`
|
||||
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 & {
|
||||
panel: IPanelProps;
|
||||
theme: EditorTheme;
|
||||
|
|
@ -646,6 +651,10 @@ const PropertyControl = memo((props: Props) => {
|
|||
onDeleteProperties([props.propertyName]);
|
||||
}
|
||||
resetEditing();
|
||||
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_EDIT_EVENT_SAVE_CLICKED", {
|
||||
widgetId: widgetProperties.widgetId,
|
||||
});
|
||||
}, [
|
||||
props,
|
||||
onBatchUpdateProperties,
|
||||
|
|
@ -657,6 +666,10 @@ const PropertyControl = memo((props: Props) => {
|
|||
const resetEditing = useCallback(() => {
|
||||
setEditedName(props.propertyName);
|
||||
setIsRenaming(false);
|
||||
|
||||
AnalyticsUtil.logEvent("CUSTOM_WIDGET_EDIT_EVENT_CANCEL_CLICKED", {
|
||||
widgetId: widgetProperties.widgetId,
|
||||
});
|
||||
}, [props.propertyName]);
|
||||
|
||||
const { propertyName } = props;
|
||||
|
|
@ -913,8 +926,15 @@ const PropertyControl = memo((props: Props) => {
|
|||
</div>
|
||||
) : (
|
||||
<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
|
||||
className="w-full"
|
||||
label={label}
|
||||
theme={props.theme}
|
||||
tooltip={helpText}
|
||||
|
|
@ -964,7 +984,7 @@ const PropertyControl = memo((props: Props) => {
|
|||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</LabelContainer>
|
||||
<div className={clsx("flex items-center justify-right")}>
|
||||
{config.controlConfig?.allowEdit && (
|
||||
<Button
|
||||
|
|
@ -975,7 +995,15 @@ const PropertyControl = memo((props: Props) => {
|
|||
)}
|
||||
isIconButton
|
||||
kind="tertiary"
|
||||
onClick={() => setIsRenaming(true)}
|
||||
onClick={() => {
|
||||
setIsRenaming(true);
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_EDIT_EVENT_CLICKED",
|
||||
{
|
||||
widgetId: widgetProperties.widgetId,
|
||||
},
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
startIcon="pencil-line"
|
||||
/>
|
||||
|
|
@ -1000,6 +1028,13 @@ const PropertyControl = memo((props: Props) => {
|
|||
onBatchUpdateProperties(updates);
|
||||
}
|
||||
onDeleteProperties([config.propertyName]);
|
||||
|
||||
AnalyticsUtil.logEvent(
|
||||
"CUSTOM_WIDGET_DELETE_EVENT_CLICKED",
|
||||
{
|
||||
widgetId: widgetProperties.widgetId,
|
||||
},
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
startIcon="trash"
|
||||
|
|
|
|||
|
|
@ -33,9 +33,9 @@ function PropertyHelpLabel(props: Props) {
|
|||
content={props.tooltip || ""}
|
||||
isDisabled={!toolTipDefined}
|
||||
>
|
||||
<div onClick={props.onClick}>
|
||||
<div className="w-full" onClick={props.onClick}>
|
||||
<Label
|
||||
className={`t--property-control-label`}
|
||||
className={`t--property-control-label w-full block text-ellipsis overflow-hidden`}
|
||||
style={{
|
||||
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(
|
||||
widget: WidgetProps,
|
||||
propertyPath: string,
|
||||
|
|
@ -400,9 +414,12 @@ function getDynamicBindingPathListUpdate(
|
|||
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.
|
||||
if (propertyPath === "primaryColumns" || propertyPath === "derivedColumns") {
|
||||
if (DYNAMIC_BINDING_IGNORED_LIST.includes(propertyPath)) {
|
||||
return {
|
||||
propertyPath,
|
||||
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)) {
|
||||
const connection = this.builderWindowConnections.get(widgetId);
|
||||
if (!skipClosing) {
|
||||
const connection = this.builderWindowConnections.get(widgetId);
|
||||
|
||||
connection?.window?.close();
|
||||
connection?.window?.close();
|
||||
}
|
||||
|
||||
this.builderWindowConnections.delete(widgetId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -291,8 +291,7 @@ export class ContainerWidget extends BaseWidget<
|
|||
{
|
||||
propertyName: "borderRadius",
|
||||
label: "Border radius",
|
||||
helpText:
|
||||
"Rounds the corners of the icon button's outer border edge",
|
||||
helpText: "Rounds the corners of the widgets's outer border edge",
|
||||
controlType: "BORDER_RADIUS_OPTIONS",
|
||||
isJSConvertible: true,
|
||||
isBindProperty: true,
|
||||
|
|
|
|||
|
|
@ -7,15 +7,22 @@ export const CUSTOM_WIDGET_LOAD_EVENTS = {
|
|||
export const getAppsmithScriptSchema = (model: Record<string, unknown>) => ({
|
||||
appsmith: {
|
||||
mode: "",
|
||||
onUiChange: Function,
|
||||
onModelChange: Function,
|
||||
updateModel: Function,
|
||||
triggerEvent: Function,
|
||||
model: model,
|
||||
ui: {
|
||||
width: 1,
|
||||
height: 2,
|
||||
},
|
||||
theme: {
|
||||
primaryColor: "",
|
||||
backgroundColor: "",
|
||||
borderRadius: "",
|
||||
boxShadow: "",
|
||||
},
|
||||
onUiChange: Function,
|
||||
onModelChange: Function,
|
||||
onThemeChange: Function,
|
||||
updateModel: Function,
|
||||
triggerEvent: Function,
|
||||
onReady: Function,
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,6 +14,15 @@ import appsmithConsole from "!!raw-loader!./appsmithConsole.js";
|
|||
import css from "!!raw-loader!./reset.css";
|
||||
import clsx from "clsx";
|
||||
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 }>`
|
||||
width: ${(props) => props.width - 8}px;
|
||||
|
|
@ -191,16 +200,26 @@ function CustomComponent(props: CustomComponentProps) {
|
|||
})}
|
||||
>
|
||||
{props.needsOverlay && <OverlayDiv data-testid="iframe-overlay" />}
|
||||
<StyledIframe
|
||||
height={props.height}
|
||||
onLoad={() => {
|
||||
setLoading(false);
|
||||
}}
|
||||
ref={iframe}
|
||||
sandbox="allow-scripts allow-downloads"
|
||||
srcDoc={srcDoc}
|
||||
width={props.width}
|
||||
/>
|
||||
<WidgetStyleContainer
|
||||
backgroundColor={props.backgroundColor}
|
||||
borderColor={props.borderColor}
|
||||
borderRadius={props.borderRadius}
|
||||
borderWidth={props.borderWidth}
|
||||
boxShadow={props.boxShadow}
|
||||
widgetId={props.widgetId}
|
||||
>
|
||||
<StyledIframe
|
||||
height={props.height}
|
||||
loading="lazy"
|
||||
onLoad={() => {
|
||||
setLoading(false);
|
||||
}}
|
||||
ref={iframe}
|
||||
sandbox="allow-scripts allow-downloads"
|
||||
srcDoc={srcDoc}
|
||||
width={props.width}
|
||||
/>
|
||||
</WidgetStyleContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -221,6 +240,30 @@ export interface CustomComponentProps {
|
|||
onConsole?: (type: string, message: string) => void;
|
||||
renderMode: "EDITOR" | "DEPLOYED" | "BUILDER";
|
||||
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);
|
||||
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 {
|
||||
|
|
@ -37,13 +36,14 @@ export default {
|
|||
|
||||
.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;
|
||||
}`,
|
||||
|
|
@ -75,7 +75,7 @@ function App() {
|
|||
</div>
|
||||
<div className="button-container">
|
||||
<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>
|
||||
</Card>
|
||||
);
|
||||
|
|
@ -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")));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<CustomWidgetProps, WidgetState> {
|
|||
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<CustomWidgetProps, WidgetState> {
|
|||
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<CustomWidgetProps, WidgetState> {
|
|||
};
|
||||
}
|
||||
|
||||
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<CustomWidgetProps, WidgetState> {
|
|||
kind="secondary"
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
to={CUSTOM_WIDGET_DOC_URL}
|
||||
to={CUSTOM_WIDGET_DEFAULT_MODEL_DOC_URL}
|
||||
>
|
||||
Read more
|
||||
</StyledLink>
|
||||
|
|
@ -190,6 +209,7 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
|||
},
|
||||
},
|
||||
dependencies: ["events"],
|
||||
helpText: "when the event is triggered from custom widget",
|
||||
}));
|
||||
},
|
||||
children: [
|
||||
|
|
@ -217,7 +237,71 @@ class CustomWidget extends BaseWidget<CustomWidgetProps, WidgetState> {
|
|||
}
|
||||
|
||||
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<CustomWidgetProps, WidgetState> {
|
|||
getWidgetView() {
|
||||
return (
|
||||
<CustomComponent
|
||||
backgroundColor={this.props.backgroundColor}
|
||||
borderColor={this.props.borderColor}
|
||||
borderRadius={this.props.borderRadius}
|
||||
borderWidth={this.props.borderWidth}
|
||||
boxShadow={this.props.boxShadow}
|
||||
execute={this.execute}
|
||||
height={this.props.componentHeight}
|
||||
model={this.props.model || {}}
|
||||
needsOverlay={
|
||||
this.props.renderMode === RenderModes.CANVAS &&
|
||||
!this.props.isWidgetSelected
|
||||
}
|
||||
renderMode={this.getRenderMode()}
|
||||
srcDoc={this.props.srcDoc}
|
||||
theme={this.props.theme}
|
||||
update={this.update}
|
||||
widgetId={this.props.widgetId}
|
||||
width={this.props.componentWidth}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user