Merge branch 'release' of github.com:appsmithorg/appsmith into release

This commit is contained in:
Arpit Mohan 2020-10-06 18:38:40 +05:30
commit 185020e9ad
17 changed files with 266 additions and 182 deletions

View File

@ -104,6 +104,8 @@ jobs:
steps:
# Checkout the code
- uses: actions/checkout@v2
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- name: Use Node.js 10.16.3
uses: actions/setup-node@v1
@ -208,6 +210,8 @@ jobs:
# Checkout the code
- uses: actions/checkout@v2
with:
ref: refs/pull/${{ github.event.pull_request.number }}/merge
- name: Download the react build artifact
uses: actions/download-artifact@v2

View File

@ -48,7 +48,7 @@ You can try our online sandbox or deploy a Docker image on a server.
When we build internal tools today, we turn to admin panels, UI frameworks or use a bootstrap theme. We took inspirations from the best admin panels, bootstrap themes, and brought back the easy UI builder of Visual Basic.
Appsmith is a quicker way of building internal tools by visualising them as modular blocks (**Widgets, APIs, Queries, JS**) and giving developers a simple user interface to configure them. Building new features, creating UI, changing dataflows, and modifying business logic becomes a [piece of cake](https://i.kym-cdn.com/photos/images/newsfeed/001/355/125/5ca.png) because you no longer have to trudge through large undocumented code bases or wrestle with HTML/CSS.
Appsmith is a quicker way of building internal tools by visualising them as modular blocks (**Widgets, APIs, Queries, JS**) and giving developers a simple user interface to configure them. Building new features, creating UI, changing dataflows, and modifying business logic becomes simpler because you no longer have to trudge through large undocumented code bases or wrestle with HTML/CSS.
Appsmith doesn't take the fun out of coding, because it treats every block as an object and exposes it via javascript so that you can read, transform and manipulate it. Whether it's a widget, API or query, you get to decide where you need to configure using UI and where you need to code.
## 🏭 Features

View File

@ -33,7 +33,6 @@ import {
DerivedPropertiesMap,
TriggerPropertiesMap,
} from "utils/WidgetFactory";
import { clearPropertyCache } from "utils/DynamicBindingUtils";
/***
* BaseWidget
@ -115,15 +114,6 @@ abstract class BaseWidget<
updateWidgetProperty(widgetId, propertyName, propertyValue);
}
updateWidgetMetaProperty(propertyName: string, propertyValue: any): void {
const { updateWidgetMetaProperty } = this.context;
const { widgetId } = this.props;
// Whenever this value updates, we need to clear cache to handle correct evaluation
clearPropertyCache(`${this.props.widgetName}.${propertyName}`);
updateWidgetMetaProperty &&
updateWidgetMetaProperty(widgetId, propertyName, propertyValue);
}
resetChildrenMetaProperty(widgetId: string) {
const { resetChildrenMetaProperty } = this.context;
resetChildrenMetaProperty(widgetId);

View File

@ -13,6 +13,7 @@ import {
DerivedPropertiesMap,
} from "utils/WidgetFactory";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
@ -63,7 +64,7 @@ class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
}
onCheckChange = (isChecked: boolean) => {
this.updateWidgetMetaProperty("isChecked", isChecked);
this.props.updateWidgetMetaProperty("isChecked", isChecked);
if (this.props.onCheckChange) {
super.executeAction({
dynamicString: this.props.onCheckChange,
@ -79,7 +80,7 @@ class CheckboxWidget extends BaseWidget<CheckboxWidgetProps, WidgetState> {
}
}
export interface CheckboxWidgetProps extends WidgetProps {
export interface CheckboxWidgetProps extends WidgetProps, WithMeta {
label: string;
defaultCheckedState: boolean;
isChecked?: boolean;
@ -88,4 +89,6 @@ export interface CheckboxWidgetProps extends WidgetProps {
}
export default CheckboxWidget;
export const ProfiledCheckboxWidget = Sentry.withProfiler(CheckboxWidget);
export const ProfiledCheckboxWidget = Sentry.withProfiler(
withMeta(CheckboxWidget),
);

View File

@ -13,6 +13,7 @@ import {
TriggerPropertiesMap,
} from "utils/WidgetFactory";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
@ -73,7 +74,7 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
}
onDateSelected = (selectedDate: string) => {
this.updateWidgetMetaProperty("selectedDate", selectedDate);
this.props.updateWidgetMetaProperty("selectedDate", selectedDate);
if (this.props.onDateSelected) {
super.executeAction({
dynamicString: this.props.onDateSelected,
@ -91,7 +92,7 @@ class DatePickerWidget extends BaseWidget<DatePickerWidgetProps, WidgetState> {
export type DatePickerType = "DATE_PICKER" | "DATE_RANGE_PICKER";
export interface DatePickerWidgetProps extends WidgetProps {
export interface DatePickerWidgetProps extends WidgetProps, WithMeta {
defaultDate: string;
selectedDate: string;
isDisabled: boolean;
@ -106,4 +107,6 @@ export interface DatePickerWidgetProps extends WidgetProps {
}
export default DatePickerWidget;
export const ProfiledDatePickerWidget = Sentry.withProfiler(DatePickerWidget);
export const ProfiledDatePickerWidget = Sentry.withProfiler(
withMeta(DatePickerWidget),
);

View File

@ -14,6 +14,7 @@ import { VALIDATORS } from "utils/Validators";
import { DataTree } from "entities/DataTree/dataTreeFactory";
import { Intent as BlueprintIntent } from "@blueprintjs/core";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
@ -95,7 +96,6 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
return {
selectedOptionValue: undefined,
selectedOptionValueArr: undefined,
selectedOptionValues: undefined,
};
}
@ -138,9 +138,9 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
onOptionSelected = (selectedOption: DropdownOption) => {
let isChanged = true;
if (this.props.selectionType === "SINGLE_SELECT") {
isChanged = !(this.props.selectedOption.value == selectedOption.value);
isChanged = !(this.props.selectedOption.value === selectedOption.value);
if (isChanged) {
this.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedOptionValue",
selectedOption.value,
);
@ -158,7 +158,10 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
} else {
newSelectedValue.push(selectedOption.value);
}
this.updateWidgetMetaProperty("selectedOptionValueArr", newSelectedValue);
this.props.updateWidgetMetaProperty(
"selectedOptionValueArr",
newSelectedValue,
);
}
if (this.props.onOptionChange && isChanged) {
@ -176,7 +179,10 @@ class DropdownWidget extends BaseWidget<DropdownWidgetProps, WidgetState> {
(v: string) =>
_.findIndex(this.props.options, { value: v }) !== removedIndex,
);
this.updateWidgetMetaProperty("selectedOptionValueArr", newSelectedValue);
this.props.updateWidgetMetaProperty(
"selectedOptionValueArr",
newSelectedValue,
);
if (this.props.onOptionChange) {
super.executeAction({
dynamicString: this.props.onOptionChange,
@ -202,7 +208,7 @@ export interface DropdownOption {
intent?: BlueprintIntent;
}
export interface DropdownWidgetProps extends WidgetProps {
export interface DropdownWidgetProps extends WidgetProps, WithMeta {
placeholderText?: string;
label?: string;
selectedIndex?: number;
@ -213,7 +219,11 @@ export interface DropdownWidgetProps extends WidgetProps {
onOptionChange?: string;
defaultOptionValue?: string | string[];
isRequired: boolean;
selectedOptionValue: string;
selectedOptionValueArr: string[];
}
export default DropdownWidget;
export const ProfiledDropDownWidget = Sentry.withProfiler(DropdownWidget);
export const ProfiledDropDownWidget = Sentry.withProfiler(
withMeta(DropdownWidget),
);

View File

@ -21,6 +21,7 @@ import Dashboard from "@uppy/dashboard";
import shallowequal from "shallowequal";
import _ from "lodash";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
class FilePickerWidget extends BaseWidget<
FilePickerWidgetProps,
@ -121,7 +122,7 @@ class FilePickerWidget extends BaseWidget<
return file.id !== dslFile.id;
})
: [];
this.updateWidgetMetaProperty("files", updatedFiles);
this.props.updateWidgetMetaProperty("files", updatedFiles);
});
this.uppy.on("file-added", (file: any) => {
const dslFiles = this.props.files || [];
@ -135,7 +136,7 @@ class FilePickerWidget extends BaseWidget<
blob: file.data,
};
dslFiles.push(newFile);
this.updateWidgetMetaProperty("files", dslFiles);
this.props.updateWidgetMetaProperty("files", dslFiles);
};
});
this.uppy.on("upload", () => {
@ -164,7 +165,7 @@ class FilePickerWidget extends BaseWidget<
handleFileUploaded = (result: ExecutionResult) => {
if (result.success) {
this.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"uploadedFileUrls",
this.props.uploadedFileUrlPaths,
);
@ -220,7 +221,7 @@ export interface FilePickerWidgetState extends WidgetState {
version: number;
}
export interface FilePickerWidgetProps extends WidgetProps {
export interface FilePickerWidgetProps extends WidgetProps, WithMeta {
label: string;
maxNumFiles?: number;
maxFileSize?: number;
@ -232,4 +233,6 @@ export interface FilePickerWidgetProps extends WidgetProps {
}
export default FilePickerWidget;
export const ProfiledFilePickerWidget = Sentry.withProfiler(FilePickerWidget);
export const ProfiledFilePickerWidget = Sentry.withProfiler(
withMeta(FilePickerWidget),
);

View File

@ -6,6 +6,7 @@ import ContainerWidget, { ContainerWidgetProps } from "widgets/ContainerWidget";
import { ContainerComponentProps } from "components/designSystems/appsmith/ContainerComponent";
import shallowEqual from "shallowequal";
import * as Sentry from "@sentry/react";
import withMeta from "./MetaHOC";
class FormWidget extends ContainerWidget {
checkInvalidChildren = (children: WidgetProps[]): boolean => {
@ -34,7 +35,7 @@ class FormWidget extends ContainerWidget {
if (this.props.children) {
const formData = this.getFormData(this.props.children[0]);
if (!shallowEqual(formData, this.props.data)) {
this.updateWidgetMetaProperty("data", formData);
this.props.updateWidgetMetaProperty("data", formData);
}
}
}
@ -73,4 +74,4 @@ export interface FormWidgetProps extends ContainerComponentProps {
}
export default FormWidget;
export const ProfiledFormWidget = Sentry.withProfiler(FormWidget);
export const ProfiledFormWidget = Sentry.withProfiler(withMeta(FormWidget));

View File

@ -15,20 +15,10 @@ import {
DerivedPropertiesMap,
TriggerPropertiesMap,
} from "utils/WidgetFactory";
import _ from "lodash";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
class InputWidget extends BaseWidget<InputWidgetProps, InputWidgetState> {
debouncedHandleTextChanged = _.debounce(
this.handleTextChanged.bind(this),
200,
);
constructor(props: InputWidgetProps) {
super(props);
this.state = {
text: props.text,
};
}
class InputWidget extends BaseWidget<InputWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
return {
...BASE_WIDGET_VALIDATION,
@ -103,28 +93,11 @@ class InputWidget extends BaseWidget<InputWidgetProps, InputWidgetState> {
};
}
componentDidUpdate(prevProps: InputWidgetProps) {
super.componentDidUpdate(prevProps);
if (
prevProps.text !== this.props.text &&
this.props.defaultText === this.props.text
) {
const text = this.props.text;
this.setState({ text });
}
}
onValueChange = (value: string) => {
this.setState({ text: value }, () => {
this.updateWidgetMetaProperty("text", value);
});
this.props.updateWidgetMetaProperty("text", value);
if (!this.props.isDirty) {
this.updateWidgetMetaProperty("isDirty", true);
this.props.updateWidgetMetaProperty("isDirty", true);
}
this.debouncedHandleTextChanged();
};
handleTextChanged() {
if (this.props.onTextChanged) {
super.executeAction({
dynamicString: this.props.onTextChanged,
@ -133,14 +106,14 @@ class InputWidget extends BaseWidget<InputWidgetProps, InputWidgetState> {
},
});
}
}
};
handleFocusChange = (focusState: boolean) => {
this.updateWidgetMetaProperty("isFocused", focusState);
this.props.updateWidgetMetaProperty("isFocused", focusState);
};
getPageView() {
const value = this.state.text || "";
const value = this.props.text || "";
const isInvalid =
"isValid" in this.props && !this.props.isValid && !!this.props.isDirty;
@ -198,7 +171,7 @@ export interface InputValidator {
validationRegex: string;
errorMessage: string;
}
export interface InputWidgetProps extends WidgetProps {
export interface InputWidgetProps extends WidgetProps, WithMeta {
inputType: InputType;
defaultText?: string;
isDisabled?: boolean;
@ -220,9 +193,5 @@ export interface InputWidgetProps extends WidgetProps {
isDirty?: boolean;
}
interface InputWidgetState extends WidgetState {
text: string;
}
export default InputWidget;
export const ProfiledInputWidget = Sentry.withProfiler(InputWidget);
export const ProfiledInputWidget = Sentry.withProfiler(withMeta(InputWidget));

View File

@ -9,6 +9,7 @@ import { TriggerPropertiesMap } from "utils/WidgetFactory";
import { getAppsmithConfigs } from "configs";
import styled from "styled-components";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
const { google } = getAppsmithConfigs();
@ -58,33 +59,33 @@ class MapWidget extends BaseWidget<MapWidgetProps, WidgetState> {
return {
center: undefined,
markers: undefined,
selectedMarker: undefined,
};
}
updateCenter = (lat: number, long: number) => {
this.updateWidgetMetaProperty("center", { lat, long });
this.props.updateWidgetMetaProperty("center", { lat, long });
};
updateMarker = (lat: number, long: number, index: number) => {
const markers: Array<MarkerProps> = [...this.props.markers];
this.disableDrag(false);
this.updateWidgetMetaProperty(
"markers",
markers.map((marker, i) => {
const markers: Array<MarkerProps> = [...this.props.markers].map(
(marker, i) => {
if (index === i) {
marker.lat = lat;
marker.long = long;
}
return marker;
}),
},
);
this.disableDrag(false);
this.props.updateWidgetMetaProperty("markers", markers);
};
onCreateMarker = (lat: number, long: number) => {
this.disableDrag(true);
this.updateWidgetMetaProperty("selectedMarker", {
lat: lat,
long: long,
this.props.updateWidgetMetaProperty("selectedMarker", {
lat,
long,
});
if (this.props.onCreateMarker) {
super.executeAction({
@ -97,12 +98,13 @@ class MapWidget extends BaseWidget<MapWidgetProps, WidgetState> {
};
onMarkerClick = (lat: number, long: number, title: string) => {
this.updateWidgetMetaProperty("selectedMarker", {
this.disableDrag(true);
const selectedMarker = {
lat: lat,
long: long,
title: title,
});
this.disableDrag(true);
};
this.props.updateWidgetMetaProperty("selectedMarker", selectedMarker);
if (this.props.onMarkerClick) {
super.executeAction({
dynamicString: this.props.onMarkerClick,
@ -172,7 +174,7 @@ export interface MarkerProps {
description?: string;
}
export interface MapWidgetProps extends WidgetProps {
export interface MapWidgetProps extends WidgetProps, WithMeta {
isDisabled?: boolean;
isVisible?: boolean;
enableSearch: boolean;
@ -199,4 +201,4 @@ export interface MapWidgetProps extends WidgetProps {
}
export default MapWidget;
export const ProfiledMapWidget = Sentry.withProfiler(MapWidget);
export const ProfiledMapWidget = Sentry.withProfiler(withMeta(MapWidget));

View File

@ -0,0 +1,90 @@
import React from "react";
import BaseWidget, { WidgetProps } from "./BaseWidget";
import _ from "lodash";
import { EditorContext } from "../components/editorComponents/EditorContextProvider";
import { clearPropertyCache } from "../utils/DynamicBindingUtils";
export interface WithMeta {
updateWidgetMetaProperty: (propertyName: string, propertyValue: any) => void;
}
const withMeta = (WrappedWidget: typeof BaseWidget) => {
return class MetaHOC extends React.Component<WidgetProps, any> {
static contextType = EditorContext;
updatedProperties = new Map<string, true>();
debouncedHandleUpdateWidgetMetaProperty = _.debounce(
this.handleUpdateWidgetMetaProperty.bind(this),
200,
{
leading: true,
trailing: true,
},
);
constructor(props: any) {
super(props);
const metaProperties = WrappedWidget.getMetaPropertiesMap();
this.state = _.fromPairs(
Object.keys(metaProperties).map(metaProperty => {
return [metaProperty, this.props[metaProperty]];
}),
);
}
componentDidUpdate(prevProps: WidgetProps) {
const metaProperties = WrappedWidget.getMetaPropertiesMap();
const defaultProperties = WrappedWidget.getDefaultPropertiesMap();
Object.keys(metaProperties).forEach(metaProperty => {
const defaultProperty = defaultProperties[metaProperty];
if (
prevProps[metaProperty] !== this.props[metaProperty] &&
this.props[defaultProperty] === this.props[metaProperty]
) {
this.setState({ [metaProperty]: this.props[metaProperty] });
}
});
}
updateWidgetMetaProperty = (
propertyName: string,
propertyValue: any,
): void => {
this.setState({
[propertyName]: propertyValue,
});
this.updatedProperties.set(propertyName, true);
this.debouncedHandleUpdateWidgetMetaProperty();
};
handleUpdateWidgetMetaProperty() {
const { updateWidgetMetaProperty } = this.context;
const { widgetId, widgetName } = this.props;
// We have kept a map of all updated properties. After debouncing we will
// go through these properties and update with the final value. This way
// we will only update a certain property once per debounce interval.
[...this.updatedProperties.keys()].forEach(propertyName => {
if (updateWidgetMetaProperty) {
const propertyValue = this.state[propertyName];
clearPropertyCache(`${widgetName}.${propertyName}`);
updateWidgetMetaProperty(widgetId, propertyName, propertyValue);
this.updatedProperties.delete(propertyName);
}
});
}
updatedProps = () => {
return {
...this.props,
...this.state,
updateWidgetMetaProperty: this.updateWidgetMetaProperty,
};
};
render() {
return <WrappedWidget {...this.updatedProps()} />;
}
};
};
export default withMeta;

View File

@ -12,6 +12,7 @@ import {
} from "constants/WidgetConstants";
import { generateClassName } from "utils/generators";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
const MODAL_SIZE: { [id: string]: { width: number; height: number } } = {
MODAL_SMALL: {
@ -48,7 +49,7 @@ class ModalWidget extends BaseWidget<ModalWidgetProps, WidgetState> {
this.props.showPropertyPane(undefined);
// TODO(abhinav): Create a static property with is a map of widget properties
// Populate the map on widget load
super.updateWidgetMetaProperty("isVisible", false);
this.props.updateWidgetMetaProperty("isVisible", false);
e.stopPropagation();
e.preventDefault();
};
@ -97,7 +98,7 @@ class ModalWidget extends BaseWidget<ModalWidgetProps, WidgetState> {
}
}
export interface ModalWidgetProps extends WidgetProps {
export interface ModalWidgetProps extends WidgetProps, WithMeta {
renderMode: RenderMode;
isOpen?: boolean;
children?: WidgetProps[];
@ -131,4 +132,4 @@ export default ModalWidget;
export const ProfiledModalWidget = connect(
null,
mapDispatchToProps,
)(Sentry.withProfiler(ModalWidget));
)(Sentry.withProfiler(withMeta(ModalWidget)));

View File

@ -10,6 +10,7 @@ import {
import { VALIDATION_TYPES } from "constants/WidgetValidation";
import { TriggerPropertiesMap } from "utils/WidgetFactory";
import * as Sentry from "@sentry/react";
import withMeta, { WithMeta } from "./MetaHOC";
class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
static getPropertyValidationMap(): WidgetPropertyValidationType {
@ -65,7 +66,7 @@ class RadioGroupWidget extends BaseWidget<RadioGroupWidgetProps, WidgetState> {
}
onRadioSelectionChange = (updatedValue: string) => {
super.updateWidgetMetaProperty("selectedOptionValue", updatedValue);
this.props.updateWidgetMetaProperty("selectedOptionValue", updatedValue);
if (this.props.onSelectionChange) {
super.executeAction({
dynamicString: this.props.onSelectionChange,
@ -86,7 +87,7 @@ export interface RadioOption {
value: string;
}
export interface RadioGroupWidgetProps extends WidgetProps {
export interface RadioGroupWidgetProps extends WidgetProps, WithMeta {
label: string;
options: RadioOption[];
selectedOptionValue: string;
@ -96,4 +97,6 @@ export interface RadioGroupWidgetProps extends WidgetProps {
}
export default RadioGroupWidget;
export const ProfiledRadioGroupWidget = Sentry.withProfiler(RadioGroupWidget);
export const ProfiledRadioGroupWidget = Sentry.withProfiler(
withMeta(RadioGroupWidget),
);

View File

@ -11,6 +11,7 @@ import {
import Skeleton from "components/utils/Skeleton";
import * as Sentry from "@sentry/react";
import { retryPromise } from "utils/AppsmithUtils";
import withMeta, { WithMeta } from "./MetaHOC";
const RichTextEditorComponent = lazy(() =>
retryPromise(() =>
@ -60,7 +61,7 @@ class RichTextEditorWidget extends BaseWidget<
}
onValueChange = (text: string) => {
this.updateWidgetMetaProperty("text", text);
this.props.updateWidgetMetaProperty("text", text);
if (this.props.onTextChange) {
super.executeAction({
dynamicString: this.props.onTextChange,
@ -92,12 +93,7 @@ class RichTextEditorWidget extends BaseWidget<
}
}
export interface InputValidator {
validationRegex: string;
errorMessage: string;
}
export interface RichTextEditorWidgetProps extends WidgetProps {
export interface RichTextEditorWidgetProps extends WidgetProps, WithMeta {
defaultText?: string;
text?: string;
placeholder?: string;
@ -108,5 +104,5 @@ export interface RichTextEditorWidgetProps extends WidgetProps {
export default RichTextEditorWidget;
export const ProfiledRichTextEditorWidget = Sentry.withProfiler(
RichTextEditorWidget,
withMeta(RichTextEditorWidget),
);

View File

@ -1,29 +1,29 @@
import React, { Suspense, lazy } from "react";
import React, { lazy, Suspense } from "react";
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
import { WidgetType } from "constants/WidgetConstants";
import { RenderModes, WidgetType } from "constants/WidgetConstants";
import { EventType } from "constants/ActionConstants";
import {
compare,
ConditionFunctions,
getAllTableColumnKeys,
renderCell,
renderActions,
renderCell,
reorderColumns,
sortTableFunction,
ConditionFunctions,
} from "components/designSystems/appsmith/TableUtilities";
import { VALIDATION_TYPES } from "constants/WidgetValidation";
import { RenderModes } from "constants/WidgetConstants";
import {
WidgetPropertyValidationType,
BASE_WIDGET_VALIDATION,
WidgetPropertyValidationType,
} from "utils/ValidationFactory";
import { ColumnAction } from "components/propertyControls/ColumnActionSelectorControl";
import { TriggerPropertiesMap } from "utils/WidgetFactory";
import Skeleton from "components/utils/Skeleton";
import moment from "moment";
import { isString, isNumber, isUndefined } from "lodash";
import { isNumber, isString, isUndefined } from "lodash";
import * as Sentry from "@sentry/react";
import { retryPromise } from "utils/AppsmithUtils";
import withMeta, { WithMeta } from "./MetaHOC";
const ReactTableComponent = lazy(() =>
retryPromise(() =>
@ -297,7 +297,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
if (!tableData || !tableData.length) {
return [];
}
let sortedTableData = [];
let sortedTableData: any[];
const searchKey = searchText ? searchText.toUpperCase() : "";
if (sortedColumn) {
const sortColumn = sortedColumn.column;
@ -311,35 +311,32 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
} else {
sortedTableData = [...tableData];
}
const filteredTableData = sortedTableData.filter(
(item: { [key: string]: any }) => {
const searchFound = searchKey
? Object.values(item)
.join(", ")
.toUpperCase()
.includes(searchKey)
: true;
if (!searchFound) return false;
if (!filters || filters.length === 0) return true;
const filterOperator: Operator =
filters.length >= 2 ? filters[1].operator : OperatorTypes.OR;
let filter = filterOperator === OperatorTypes.AND ? true : false;
for (let i = 0; i < filters.length; i++) {
const filterValue = compare(
item[filters[i].column],
filters[i].value,
filters[i].condition,
);
if (filterOperator === OperatorTypes.AND) {
filter = filter && filterValue;
} else {
filter = filter || filterValue;
}
return sortedTableData.filter((item: { [key: string]: any }) => {
const searchFound = searchKey
? Object.values(item)
.join(", ")
.toUpperCase()
.includes(searchKey)
: true;
if (!searchFound) return false;
if (!filters || filters.length === 0) return true;
const filterOperator: Operator =
filters.length >= 2 ? filters[1].operator : OperatorTypes.OR;
let filter = filterOperator === OperatorTypes.AND;
for (let i = 0; i < filters.length; i++) {
const filterValue = compare(
item[filters[i].column],
filters[i].value,
filters[i].condition,
);
if (filterOperator === OperatorTypes.AND) {
filter = filter && filterValue;
} else {
filter = filter || filterValue;
}
return filter;
},
);
return filteredTableData;
}
return filter;
});
};
getSelectedRow = (filteredTableData: object[], selectedRowIndex?: number) => {
@ -356,9 +353,9 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
componentDidMount() {
const filteredTableData = this.filterTableData();
super.updateWidgetMetaProperty("filteredTableData", filteredTableData);
this.props.updateWidgetMetaProperty("filteredTableData", filteredTableData);
const { selectedRowIndex } = this.props;
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedRow",
this.getSelectedRow(filteredTableData, selectedRowIndex),
);
@ -377,14 +374,17 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
!this.props.filteredTableData
) {
const filteredTableData = this.filterTableData();
super.updateWidgetMetaProperty("filteredTableData", filteredTableData);
this.props.updateWidgetMetaProperty(
"filteredTableData",
filteredTableData,
);
if (!this.props.multiRowSelection) {
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedRow",
this.getSelectedRow(filteredTableData),
);
} else {
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedRows",
filteredTableData.filter((item: object, i: number) => {
return this.props.selectedRowIndices.includes(i);
@ -393,36 +393,36 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
}
}
if (tableDataUpdated) {
super.updateWidgetMetaProperty("selectedRowIndices", []);
super.updateWidgetMetaProperty("selectedRows", []);
super.updateWidgetMetaProperty("selectedRowIndex", -1);
this.props.updateWidgetMetaProperty("selectedRowIndices", []);
this.props.updateWidgetMetaProperty("selectedRows", []);
this.props.updateWidgetMetaProperty("selectedRowIndex", -1);
}
if (this.props.multiRowSelection !== prevProps.multiRowSelection) {
if (this.props.multiRowSelection) {
const selectedRowIndices = this.props.selectedRowIndex
? [this.props.selectedRowIndex]
: [];
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedRowIndices",
selectedRowIndices,
);
super.updateWidgetMetaProperty("selectedRowIndex", -1);
this.props.updateWidgetMetaProperty("selectedRowIndex", -1);
const filteredTableData = this.filterTableData();
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedRows",
filteredTableData.filter((item: object, i: number) => {
return selectedRowIndices.includes(i);
}),
);
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedRow",
this.getSelectedRow(filteredTableData),
);
} else {
const filteredTableData = this.filterTableData();
super.updateWidgetMetaProperty("selectedRowIndices", []);
super.updateWidgetMetaProperty("selectedRows", []);
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty("selectedRowIndices", []);
this.props.updateWidgetMetaProperty("selectedRows", []);
this.props.updateWidgetMetaProperty(
"selectedRow",
this.getSelectedRow(filteredTableData),
);
@ -456,7 +456,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
if (pageNo === undefined) {
pageNo = 1;
super.updateWidgetMetaProperty("pageNo", pageNo);
this.props.updateWidgetMetaProperty("pageNo", pageNo);
}
const { componentWidth, componentHeight } = this.getComponentDimensions();
const tableSizes =
@ -477,7 +477,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
pageSize += 1;
if (pageSize !== this.props.pageSize) {
super.updateWidgetMetaProperty("pageSize", pageSize);
this.props.updateWidgetMetaProperty("pageSize", pageSize);
}
return (
<Suspense fallback={<Skeleton />}>
@ -511,7 +511,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
nextPageClick={this.handleNextPageClick}
prevPageClick={this.handlePrevPageClick}
updatePageNo={(pageNo: number) => {
super.updateWidgetMetaProperty("pageNo", pageNo);
this.props.updateWidgetMetaProperty("pageNo", pageNo);
}}
updateHiddenColumns={(hiddenColumns?: string[]) => {
super.updateWidgetProperty("hiddenColumns", hiddenColumns);
@ -538,14 +538,14 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
filters={this.props.filters}
applyFilter={(filters: ReactTableFilter[]) => {
this.resetSelectedRowIndex();
super.updateWidgetMetaProperty("filters", filters);
this.props.updateWidgetMetaProperty("filters", filters);
}}
compactMode={this.props.compactMode || CompactModeTypes.DEFAULT}
updateCompactMode={(compactMode: CompactMode) => {
if (this.props.renderMode === RenderModes.CANVAS) {
super.updateWidgetProperty("compactMode", compactMode);
this.props.updateWidgetMetaProperty("compactMode", compactMode);
} else {
super.updateWidgetMetaProperty("compactMode", compactMode);
this.props.updateWidgetMetaProperty("compactMode", compactMode);
}
}}
sortTableColumn={this.handleColumnSorting}
@ -557,9 +557,9 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
handleColumnSorting = (column: string, asc: boolean) => {
this.resetSelectedRowIndex();
if (column === "") {
super.updateWidgetMetaProperty("sortedColumn", undefined);
this.props.updateWidgetMetaProperty("sortedColumn", undefined);
} else {
super.updateWidgetMetaProperty("sortedColumn", {
this.props.updateWidgetMetaProperty("sortedColumn", {
column: column,
asc: asc,
});
@ -569,8 +569,8 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
handleSearchTable = (searchKey: any) => {
const { onSearchTextChanged } = this.props;
this.resetSelectedRowIndex();
this.updateWidgetMetaProperty("pageNo", 1);
super.updateWidgetMetaProperty("searchText", searchKey);
this.props.updateWidgetMetaProperty("pageNo", 1);
this.props.updateWidgetMetaProperty("searchText", searchKey);
if (onSearchTextChanged) {
super.executeAction({
dynamicString: onSearchTextChanged,
@ -604,16 +604,19 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
} else {
selectedRowIndices.push(index);
}
super.updateWidgetMetaProperty("selectedRowIndices", selectedRowIndices);
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty(
"selectedRowIndices",
selectedRowIndices,
);
this.props.updateWidgetMetaProperty(
"selectedRows",
this.props.filteredTableData.filter((item: object, i: number) => {
return selectedRowIndices.includes(i);
}),
);
} else {
super.updateWidgetMetaProperty("selectedRowIndex", index);
super.updateWidgetMetaProperty(
this.props.updateWidgetMetaProperty("selectedRowIndex", index);
this.props.updateWidgetMetaProperty(
"selectedRow",
this.props.filteredTableData[index],
);
@ -631,7 +634,7 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
handleNextPageClick = () => {
let pageNo = this.props.pageNo || 1;
pageNo = pageNo + 1;
super.updateWidgetMetaProperty("pageNo", pageNo);
this.props.updateWidgetMetaProperty("pageNo", pageNo);
if (this.props.onPageChange) {
this.resetSelectedRowIndex();
super.executeAction({
@ -644,15 +647,15 @@ class TableWidget extends BaseWidget<TableWidgetProps, WidgetState> {
};
resetSelectedRowIndex = () => {
super.updateWidgetMetaProperty("selectedRowIndex", -1);
super.updateWidgetMetaProperty("selectedRowIndices", []);
this.props.updateWidgetMetaProperty("selectedRowIndex", -1);
this.props.updateWidgetMetaProperty("selectedRowIndices", []);
};
handlePrevPageClick = () => {
let pageNo = this.props.pageNo || 1;
pageNo = pageNo - 1;
if (pageNo >= 1) {
super.updateWidgetMetaProperty("pageNo", pageNo);
this.props.updateWidgetMetaProperty("pageNo", pageNo);
if (this.props.onPageChange) {
this.resetSelectedRowIndex();
super.executeAction({
@ -697,7 +700,7 @@ export interface ReactTableColumnProps {
Cell: (props: any) => JSX.Element;
}
export interface TableWidgetProps extends WidgetProps {
export interface TableWidgetProps extends WidgetProps, WithMeta {
nextPageKey?: string;
prevPageKey?: string;
label: string;
@ -729,4 +732,4 @@ export interface TableWidgetProps extends WidgetProps {
}
export default TableWidget;
export const ProfiledTableWidget = Sentry.withProfiler(TableWidget);
export const ProfiledTableWidget = Sentry.withProfiler(withMeta(TableWidget));

View File

@ -10,6 +10,7 @@ import { EventType } from "constants/ActionConstants";
import { WidgetOperations } from "widgets/BaseWidget";
import * as Sentry from "@sentry/react";
import { generateReactKey } from "utils/generators";
import withMeta, { WithMeta } from "./MetaHOC";
class TabsWidget extends BaseWidget<
TabsWidgetProps<TabContainerWidgetProps>,
@ -23,7 +24,7 @@ class TabsWidget extends BaseWidget<
}
onTabChange = (tabId: string) => {
this.updateWidgetMetaProperty("selectedTabId", tabId);
this.props.updateWidgetMetaProperty("selectedTabId", tabId);
if (this.props.onTabSelected) {
super.executeAction({
dynamicString: this.props.onTabSelected,
@ -174,7 +175,7 @@ class TabsWidget extends BaseWidget<
label: this.props.defaultTab,
});
const selectedTabId = selectedTab ? selectedTab.id : undefined;
this.updateWidgetMetaProperty("selectedTabId", selectedTabId);
this.props.updateWidgetMetaProperty("selectedTabId", selectedTabId);
}
}
}
@ -227,12 +228,15 @@ class TabsWidget extends BaseWidget<
// If we have a legitimate default tab Id and it is not already the selected Tab
if (selectedTabId && selectedTabId !== this.props.selectedTabId) {
// Select the default tab
this.updateWidgetMetaProperty("selectedTabId", selectedTabId);
this.props.updateWidgetMetaProperty("selectedTabId", selectedTabId);
}
} else if (!this.props.selectedTabId) {
// If no tab is selected
// Select the first tab in the tabs list.
this.updateWidgetMetaProperty("selectedTabId", this.props.tabs[0].id);
this.props.updateWidgetMetaProperty(
"selectedTabId",
this.props.tabs[0].id,
);
}
this.generateTabContainers();
}
@ -243,7 +247,8 @@ export interface TabContainerWidgetProps extends WidgetProps {
}
export interface TabsWidgetProps<T extends TabContainerWidgetProps>
extends WidgetProps {
extends WidgetProps,
WithMeta {
isVisible?: boolean;
shouldScrollContents: boolean;
tabs: Array<{
@ -261,4 +266,4 @@ export interface TabsWidgetProps<T extends TabContainerWidgetProps>
}
export default TabsWidget;
export const ProfiledTabsWidget = Sentry.withProfiler(TabsWidget);
export const ProfiledTabsWidget = Sentry.withProfiler(withMeta(TabsWidget));

View File

@ -12,6 +12,7 @@ import Skeleton from "components/utils/Skeleton";
import * as Sentry from "@sentry/react";
import { retryPromise } from "utils/AppsmithUtils";
import ReactPlayer from "react-player";
import withMeta, { WithMeta } from "./MetaHOC";
const VideoComponent = lazy(() =>
retryPromise(() =>
@ -67,7 +68,7 @@ class VideoWidget extends BaseWidget<VideoWidgetProps, WidgetState> {
autoplay={autoPlay}
controls={true}
onPlay={() => {
this.updateWidgetMetaProperty("playState", PlayState.PLAYING);
this.props.updateWidgetMetaProperty("playState", PlayState.PLAYING);
if (onPlay) {
super.executeAction({
dynamicString: onPlay,
@ -79,7 +80,7 @@ class VideoWidget extends BaseWidget<VideoWidgetProps, WidgetState> {
}}
onPause={() => {
//TODO: We do not want the pause event for onSeek or onEnd.
this.updateWidgetMetaProperty("playState", PlayState.PAUSED);
this.props.updateWidgetMetaProperty("playState", PlayState.PAUSED);
if (onPause) {
super.executeAction({
dynamicString: onPause,
@ -90,7 +91,7 @@ class VideoWidget extends BaseWidget<VideoWidgetProps, WidgetState> {
}
}}
onEnded={() => {
this.updateWidgetMetaProperty("playState", PlayState.ENDED);
this.props.updateWidgetMetaProperty("playState", PlayState.ENDED);
if (onEnd) {
super.executeAction({
dynamicString: onEnd,
@ -110,7 +111,7 @@ class VideoWidget extends BaseWidget<VideoWidgetProps, WidgetState> {
}
}
export interface VideoWidgetProps extends WidgetProps {
export interface VideoWidgetProps extends WidgetProps, WithMeta {
url: string;
autoPlay: boolean;
onPause?: string;
@ -119,4 +120,4 @@ export interface VideoWidgetProps extends WidgetProps {
}
export default VideoWidget;
export const ProfiledVideoWidget = Sentry.withProfiler(VideoWidget);
export const ProfiledVideoWidget = Sentry.withProfiler(withMeta(VideoWidget));