PromucFlow_constructor/app/client/src/widgets/IframeWidget/widget/index.tsx
Preet Sidhu 69f4a412bf
chore: add highlight calculation logic for layouts. (#27980)
## Description

1. Add LayoutComponent functionality.
2. Create Basic LayoutComponents.
3. Create LayoutPresets needed for Container-like widgets.
4. Add highlight calculation logic for all basic Layout Components.
5. Create dragging sagas for Anvil.
6. Create DraggingArena associated functionality to handle DnD in Anvil.

#### PR fixes following issue(s)
Fixes #27004 


#### Type of change
> Please delete options that are not relevant.
- New feature (non-breaking change which adds functionality)

## Testing

#### How Has This Been Tested?
- [ ] Manual
- [ ] JUnit
- [x] Jest
- [ ] Cypress


## Checklist:
#### Dev activity
- [x] My code follows the style guidelines of this project
- [x] I have performed a self-review of my own code
- [x] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] 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

---------

Co-authored-by: Ashok Kumar M <35134347+marks0351@users.noreply.github.com>
Co-authored-by: Aswath K <aswath.sana@gmail.com>
Co-authored-by: rahulramesha <rahul@appsmith.com>
Co-authored-by: rahulramesha <71900764+rahulramesha@users.noreply.github.com>
2023-10-19 16:27:40 -04:00

392 lines
11 KiB
TypeScript

import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
import { ValidationTypes } from "constants/WidgetValidation";
import type { SetterConfig, Stylesheet } from "entities/AppTheming";
import React from "react";
import type { WidgetState } from "widgets/BaseWidget";
import BaseWidget from "widgets/BaseWidget";
import IframeComponent from "../component";
import type { IframeWidgetProps } from "../constants";
import { generateTypeDef } from "utils/autocomplete/dataTreeTypeDefCreator";
import { DefaultAutocompleteDefinitions } from "widgets/WidgetUtils";
import type {
AnvilConfig,
AutocompletionDefinitions,
} from "WidgetProvider/constants";
import IconSVG from "../icon.svg";
import { isAirgapped } from "@appsmith/utils/airgapHelpers";
import type {
SnipingModeProperty,
PropertyUpdates,
} from "WidgetProvider/constants";
import { WIDGET_TAGS } from "constants/WidgetConstants";
import {
FlexVerticalAlignment,
ResponsiveBehavior,
} from "layoutSystems/common/utils/constants";
const isAirgappedInstance = isAirgapped();
const DEFAULT_IFRAME_SOURCE = !isAirgappedInstance
? "https://www.example.com"
: "";
class IframeWidget extends BaseWidget<IframeWidgetProps, WidgetState> {
static type = "IFRAME_WIDGET";
static getConfig() {
return {
name: "Iframe",
iconSVG: IconSVG,
tags: [WIDGET_TAGS.DISPLAY],
needsMeta: true,
searchTags: ["embed"],
};
}
static getDefaults() {
return {
source: DEFAULT_IFRAME_SOURCE,
borderOpacity: 100,
borderWidth: 1,
rows: 32,
columns: 24,
widgetName: "Iframe",
version: 1,
animateLoading: true,
responsiveBehavior: ResponsiveBehavior.Fill,
flexVerticalAlignment: FlexVerticalAlignment.Top,
};
}
static getMethods() {
return {
getSnipingModeUpdates: (
propValueMap: SnipingModeProperty,
): PropertyUpdates[] => {
return [
{
propertyPath: "source",
propertyValue: propValueMap.data,
isDynamicPropertyPath: true,
},
];
},
};
}
static getAutoLayoutConfig() {
return {
widgetSize: [
{
viewportMinWidth: 0,
configuration: () => {
return {
minWidth: "280px",
minHeight: "300px",
};
},
},
],
};
}
static getAnvilConfig(): AnvilConfig | null {
return {
widgetSize: {
maxHeight: {},
maxWidth: {},
minHeight: { base: "300px" },
minWidth: { base: "280px" },
},
};
}
static getAutocompleteDefinitions(): AutocompletionDefinitions {
return (widget: IframeWidgetProps) => ({
"!doc": "Iframe widget is used to display iframes in your app.",
"!url": "https://docs.appsmith.com/widget-reference/iframe",
isVisible: DefaultAutocompleteDefinitions.isVisible,
source: "string",
title: "string",
message: generateTypeDef(widget.message),
messageMetadata: generateTypeDef(widget.messageMetadata),
});
}
static getSetterConfig(): SetterConfig {
return {
__setters: {
setVisibility: {
path: "isVisible",
type: "boolean",
},
setURL: {
path: "source",
type: "string",
},
},
};
}
static getPropertyPaneContentConfig() {
return [
{
sectionName: "Data",
children: [
{
propertyName: "source",
helpText: "The URL of the page to embed",
label: "URL",
controlType: "INPUT_TEXT",
placeholderText: "https://docs.appsmith.com",
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.SAFE_URL,
params: {
default: "https://www.example.com",
},
},
},
{
propertyName: "srcDoc",
helpText: "Inline HTML to embed, overriding the src attribute",
label: "srcDoc",
controlType: "INPUT_TEXT",
placeholderText: "<p>Inline HTML</p>",
isBindProperty: true,
isTriggerProperty: false,
validation: {
type: ValidationTypes.TEXT,
},
},
],
},
{
sectionName: "General",
children: [
{
propertyName: "title",
helpText: "Label the content of the page to embed",
label: "Title",
controlType: "INPUT_TEXT",
placeholderText: "Documentation",
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
{
propertyName: "animateLoading",
label: "Animate loading",
controlType: "SWITCH",
helpText: "Controls the loading of the widget",
defaultValue: true,
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.BOOLEAN },
},
],
},
{
sectionName: "Events",
children: [
{
helpText: "when the source URL is changed",
propertyName: "onURLChanged",
label: "onURLChanged",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
{
helpText: "when the srcDoc is changed",
propertyName: "onSrcDocChanged",
label: "onSrcDocChanged",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
{
helpText: "when a message event is received",
propertyName: "onMessageReceived",
label: "onMessageReceived",
controlType: "ACTION_SELECTOR",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: true,
},
],
},
];
}
static getPropertyPaneStyleConfig() {
return [
{
sectionName: "Color",
children: [
{
propertyName: "borderColor",
label: "Border color",
helpText: "Controls the color of the border",
controlType: "COLOR_PICKER",
isJSConvertible: true,
isBindProperty: true,
isTriggerProperty: false,
validation: { type: ValidationTypes.TEXT },
},
],
},
{
sectionName: "Border and shadow",
children: [
{
propertyName: "borderWidth",
label: "Border width (px)",
helpText: "Controls the size of the border in px",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
inputType: "NUMBER",
validation: {
type: ValidationTypes.NUMBER,
params: { min: 0, default: 1 },
},
},
{
propertyName: "borderOpacity",
label: "Border opacity (%)",
helpText: "Controls the opacity of the border in percentage",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
inputType: "NUMBER",
validation: {
type: ValidationTypes.NUMBER,
params: { min: 0, max: 100, default: 100 },
},
},
{
propertyName: "borderRadius",
label: "Border radius",
helpText:
"Rounds the corners of the icon button'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 getMetaPropertiesMap(): Record<string, any> {
return {
message: undefined,
messageMetadata: undefined,
};
}
static getStylesheetConfig(): Stylesheet {
return {
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "{{appsmith.theme.boxShadow.appBoxShadow}}",
};
}
handleUrlChange = (url: string) => {
if (url && this.props.onURLChanged) {
super.executeAction({
triggerPropertyName: "onURLChanged",
dynamicString: this.props.onURLChanged,
event: {
type: EventType.ON_IFRAME_URL_CHANGED,
},
});
}
};
handleSrcDocChange = (srcDoc?: string) => {
if (srcDoc && this.props.onSrcDocChanged) {
super.executeAction({
triggerPropertyName: "onSrcDocChanged",
dynamicString: this.props.onSrcDocChanged,
event: {
type: EventType.ON_IFRAME_SRC_DOC_CHANGED,
},
});
}
};
handleMessageReceive = ({
data,
lastEventId,
origin,
ports,
}: MessageEvent) => {
this.props.updateWidgetMetaProperty("messageMetadata", {
lastEventId,
origin,
ports,
});
this.props.updateWidgetMetaProperty("message", data, {
triggerPropertyName: "onMessageReceived",
dynamicString: this.props.onMessageReceived,
event: {
type: EventType.ON_IFRAME_MESSAGE_RECEIVED,
},
});
};
getWidgetView() {
const {
borderColor,
borderOpacity,
borderWidth,
renderMode,
source,
srcDoc,
title,
widgetId,
widgetName,
} = this.props;
return (
<IframeComponent
borderColor={borderColor}
borderOpacity={borderOpacity}
borderRadius={this.props.borderRadius}
borderWidth={borderWidth}
boxShadow={this.props.boxShadow}
onMessageReceived={this.handleMessageReceive}
onSrcDocChanged={this.handleSrcDocChange}
onURLChanged={this.handleUrlChange}
renderMode={renderMode}
source={source}
srcDoc={srcDoc}
title={title}
widgetId={widgetId}
widgetName={widgetName}
/>
);
}
}
export default IframeWidget;