Fix: Tabs widget refactor with new nested property validation (#4014)
* dip * test cases first commit * Adding Tabs migrator. * fixing tests. * bug fix. * selected tab fix * missed commit * fixing bugs * Fixing tab name bugs. * close property pane when dragging or resizing * migration changes. * release rebase changes. * adding List factory * remove dynamic bindings on deleting tabs. * Adding validation messages for nested properties as well * fixing validation issue. * tabs visibility validation. * missed commit * Fixing broken cypress tests. * Fixing broken tests.
This commit is contained in:
parent
0b2bd452df
commit
8f7cc87801
|
|
@ -22,10 +22,13 @@ describe("Container Widget Functionality", function() {
|
||||||
/**
|
/**
|
||||||
* @param{Text} Random Colour
|
* @param{Text} Random Colour
|
||||||
*/
|
*/
|
||||||
cy.testCodeMirror(this.data.colour);
|
cy.get(widgetsPage.backgroundcolorPicker)
|
||||||
|
.first()
|
||||||
|
.click({ force: true });
|
||||||
|
cy.xpath(widgetsPage.greenColor).click();
|
||||||
cy.get(widgetsPage.containerD)
|
cy.get(widgetsPage.containerD)
|
||||||
.should("have.css", "background-color")
|
.should("have.css", "background-color")
|
||||||
.and("eq", this.data.rgbValue);
|
.and("eq", "rgb(3, 179, 101)");
|
||||||
/**
|
/**
|
||||||
* @param{toggleButton Css} Assert to be checked
|
* @param{toggleButton Css} Assert to be checked
|
||||||
*/
|
*/
|
||||||
|
|
@ -41,7 +44,7 @@ describe("Container Widget Functionality", function() {
|
||||||
cy.get(widgetsPage.containerD)
|
cy.get(widgetsPage.containerD)
|
||||||
.eq(0)
|
.eq(0)
|
||||||
.should("have.css", "background-color")
|
.should("have.css", "background-color")
|
||||||
.and("eq", this.data.rgbValue);
|
.and("eq", "rgb(3, 179, 101)");
|
||||||
});
|
});
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
// put your clean up code if any
|
// put your clean up code if any
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@
|
||||||
"verticalCenter": ".t--icon-tab-CENTER",
|
"verticalCenter": ".t--icon-tab-CENTER",
|
||||||
"verticalBottom": ".t--icon-tab-BOTTOM",
|
"verticalBottom": ".t--icon-tab-BOTTOM",
|
||||||
"textColor": ".t--property-control-textcolor input",
|
"textColor": ".t--property-control-textcolor input",
|
||||||
|
"backgroundcolorPicker": ".t--property-control-backgroundcolor input",
|
||||||
"greenColor": "//div[@color='rgb(3, 179, 101)']",
|
"greenColor": "//div[@color='rgb(3, 179, 101)']",
|
||||||
"toggleJsColor": ".t--property-control-textcolor .t--js-toggle",
|
"toggleJsColor": ".t--property-control-textcolor .t--js-toggle",
|
||||||
"backgroundColor": ".t--property-control-cellbackground input",
|
"backgroundColor": ".t--property-control-cellbackground input",
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ module.exports = {
|
||||||
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node", "css"],
|
moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "node", "css"],
|
||||||
moduleDirectories: ["node_modules", "src", "test"],
|
moduleDirectories: ["node_modules", "src", "test"],
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
"<rootDir>/node_modules/(?!codemirror|react-dnd|dnd-core|@babel|(@blueprintjs/core/lib/esnext)|(@blueprintjs/core/lib/esm)|@github)",
|
"<rootDir>/node_modules/(?!codemirror|react-dnd|dnd-core|@babel|(@blueprintjs/core/lib/esnext)|(@blueprintjs/core/lib/esm)|@github|lodash-es)",
|
||||||
],
|
],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
"\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js",
|
"\\.(css|less)$": "<rootDir>/test/__mocks__/styleMock.js",
|
||||||
|
|
@ -23,6 +23,7 @@ module.exports = {
|
||||||
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
|
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$":
|
||||||
"<rootDir>/test/__mocks__/fileMock.js",
|
"<rootDir>/test/__mocks__/fileMock.js",
|
||||||
"^worker-loader!": "<rootDir>/test/__mocks__/workerMock.js",
|
"^worker-loader!": "<rootDir>/test/__mocks__/workerMock.js",
|
||||||
|
"^!!raw-loader!": "<rootDir>/test/__mocks__/derivedMock.js",
|
||||||
"test/(.*)": "<rootDir>/test/$1",
|
"test/(.*)": "<rootDir>/test/$1",
|
||||||
},
|
},
|
||||||
globals: {
|
globals: {
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,7 @@
|
||||||
"start-prod": "REACT_APP_ENVIRONMENT=PRODUCTION craco start",
|
"start-prod": "REACT_APP_ENVIRONMENT=PRODUCTION craco start",
|
||||||
"cytest": "REACT_APP_TESTING=TESTING REACT_APP_ENVIRONMENT=DEVELOPMENT craco start & ./node_modules/.bin/cypress open",
|
"cytest": "REACT_APP_TESTING=TESTING REACT_APP_ENVIRONMENT=DEVELOPMENT craco start & ./node_modules/.bin/cypress open",
|
||||||
"test:unit": "$(npm bin)/jest -b --colors --no-cache --coverage --collectCoverage=true --coverageDirectory='../../' --coverageReporters='json-summary'",
|
"test:unit": "$(npm bin)/jest -b --colors --no-cache --coverage --collectCoverage=true --coverageDirectory='../../' --coverageReporters='json-summary'",
|
||||||
|
"test:jest": "$(npm bin)/jest --watch",
|
||||||
"storybook": "start-storybook -p 9009 -s public",
|
"storybook": "start-storybook -p 9009 -s public",
|
||||||
"build-storybook": "build-storybook -s public"
|
"build-storybook": "build-storybook -s public"
|
||||||
},
|
},
|
||||||
|
|
@ -212,6 +213,7 @@
|
||||||
"eslint-plugin-prettier": "^3.1.4",
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
"eslint-plugin-react": "^7.21.3",
|
"eslint-plugin-react": "^7.21.3",
|
||||||
"eslint-plugin-react-hooks": "^2.3.0",
|
"eslint-plugin-react-hooks": "^2.3.0",
|
||||||
|
"factory.ts": "^0.5.1",
|
||||||
"jest-canvas-mock": "^2.3.1",
|
"jest-canvas-mock": "^2.3.1",
|
||||||
"mocha": "^7.1.0",
|
"mocha": "^7.1.0",
|
||||||
"mocha-junit-reporter": "^1.23.3",
|
"mocha-junit-reporter": "^1.23.3",
|
||||||
|
|
|
||||||
|
|
@ -227,12 +227,23 @@ export type WidgetAddChildren = {
|
||||||
}>;
|
}>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type WidgetUpdateProperty = {
|
||||||
|
widgetId: string;
|
||||||
|
propertyPath: string;
|
||||||
|
propertyValue: any;
|
||||||
|
};
|
||||||
|
|
||||||
export const updateWidget = (
|
export const updateWidget = (
|
||||||
operation: WidgetOperation,
|
operation: WidgetOperation,
|
||||||
widgetId: string,
|
widgetId: string,
|
||||||
payload: any,
|
payload: any,
|
||||||
): ReduxAction<
|
): ReduxAction<
|
||||||
WidgetAddChild | WidgetMove | WidgetResize | WidgetDelete | WidgetAddChildren
|
| WidgetAddChild
|
||||||
|
| WidgetMove
|
||||||
|
| WidgetResize
|
||||||
|
| WidgetDelete
|
||||||
|
| WidgetAddChildren
|
||||||
|
| WidgetUpdateProperty
|
||||||
> => {
|
> => {
|
||||||
return {
|
return {
|
||||||
type: ReduxActionTypes["WIDGET_" + operation],
|
type: ReduxActionTypes["WIDGET_" + operation],
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import React, { RefObject, ReactNode, useEffect, useRef } from "react";
|
import React, { RefObject, ReactNode, useEffect, useRef } from "react";
|
||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
import { ComponentProps } from "./BaseComponent";
|
import { ComponentProps } from "./BaseComponent";
|
||||||
import { TabsWidgetProps, TabContainerWidgetProps } from "widgets/TabsWidget";
|
import {
|
||||||
|
TabsWidgetProps,
|
||||||
|
TabContainerWidgetProps,
|
||||||
|
} from "widgets/Tabs/TabsWidget";
|
||||||
import { generateClassName, getCanvasClassName } from "utils/generators";
|
import { generateClassName, getCanvasClassName } from "utils/generators";
|
||||||
import { getBorderCSSShorthand } from "constants/DefaultTheme";
|
import { getBorderCSSShorthand } from "constants/DefaultTheme";
|
||||||
import ScrollIndicator from "components/ads/ScrollIndicator";
|
import ScrollIndicator from "components/ads/ScrollIndicator";
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,7 @@ class PrimaryColumnsControl extends BaseControl<ControlProps> {
|
||||||
|
|
||||||
this.props.openNextPanel({
|
this.props.openNextPanel({
|
||||||
...originalColumn,
|
...originalColumn,
|
||||||
widgetId: this.props.widgetProperties.widgetId,
|
propPaneId: this.props.widgetProperties.widgetId,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
//Used to reorder columns
|
//Used to reorder columns
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import React, { useState } from "react";
|
import React, { useCallback } from "react";
|
||||||
import BaseControl, { ControlProps } from "./BaseControl";
|
import BaseControl, { ControlProps } from "./BaseControl";
|
||||||
import {
|
import {
|
||||||
StyledHiddenIcon,
|
|
||||||
StyledInputGroup,
|
StyledInputGroup,
|
||||||
StyledPropertyPaneButton,
|
StyledPropertyPaneButton,
|
||||||
StyledVisibleIcon,
|
|
||||||
StyledDragIcon,
|
StyledDragIcon,
|
||||||
StyledDeleteIcon,
|
StyledDeleteIcon,
|
||||||
|
StyledEditIcon,
|
||||||
} from "./StyledControls";
|
} from "./StyledControls";
|
||||||
import styled from "constants/DefaultTheme";
|
import styled from "constants/DefaultTheme";
|
||||||
import { generateReactKey } from "utils/generators";
|
import { generateReactKey } from "utils/generators";
|
||||||
|
|
@ -63,12 +62,15 @@ type RenderComponentProps = {
|
||||||
deleteOption: (index: number) => void;
|
deleteOption: (index: number) => void;
|
||||||
updateOption: (index: number, value: string) => void;
|
updateOption: (index: number, value: string) => void;
|
||||||
toggleVisibility?: (index: number) => void;
|
toggleVisibility?: (index: number) => void;
|
||||||
|
onEdit?: (props: any) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
function TabControlComponent(props: RenderComponentProps) {
|
function TabControlComponent(props: RenderComponentProps) {
|
||||||
const { deleteOption, updateOption, item, index, toggleVisibility } = props;
|
const { deleteOption, updateOption, item, index } = props;
|
||||||
const debouncedUpdate = debounce(updateOption, 1000);
|
const debouncedUpdate = debounce(updateOption, 1000);
|
||||||
const [visibility, setVisibility] = useState(item.isVisible);
|
const handleChange = useCallback(() => props.onEdit && props.onEdit(index), [
|
||||||
|
index,
|
||||||
|
]);
|
||||||
return (
|
return (
|
||||||
<ItemWrapper>
|
<ItemWrapper>
|
||||||
<StyledDragIcon height={20} width={20} />
|
<StyledDragIcon height={20} width={20} />
|
||||||
|
|
@ -89,29 +91,12 @@ function TabControlComponent(props: RenderComponentProps) {
|
||||||
deleteOption(index);
|
deleteOption(index);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{visibility || visibility === undefined ? (
|
<StyledEditIcon
|
||||||
<StyledVisibleIcon
|
className="t--edit-column-btn"
|
||||||
className="t--show-tab-btn"
|
|
||||||
height={20}
|
height={20}
|
||||||
width={20}
|
width={20}
|
||||||
marginRight={36}
|
onClick={handleChange}
|
||||||
onClick={() => {
|
|
||||||
setVisibility(!visibility);
|
|
||||||
toggleVisibility && toggleVisibility(index);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
|
||||||
<StyledHiddenIcon
|
|
||||||
className="t--show-tab-btn"
|
|
||||||
height={20}
|
|
||||||
width={20}
|
|
||||||
marginRight={36}
|
|
||||||
onClick={() => {
|
|
||||||
setVisibility(!visibility);
|
|
||||||
toggleVisibility && toggleVisibility(index);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ItemWrapper>
|
</ItemWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -148,15 +133,37 @@ class TabControl extends BaseControl<ControlProps> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateItems = (items: Array<Record<string, unknown>>) => {
|
updateItems = (items: Array<Record<string, any>>) => {
|
||||||
this.updateProperty(this.props.propertyName, items);
|
const tabsObj = items.reduce((obj: any, each: any, index: number) => {
|
||||||
|
obj[each.id] = {
|
||||||
|
...each,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
this.updateProperty(this.props.propertyName, tabsObj);
|
||||||
|
};
|
||||||
|
|
||||||
|
onEdit = (index: number) => {
|
||||||
|
const tabs: Array<{
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
}> = Object.values(this.props.propertyValue);
|
||||||
|
const tabToChange = tabs[index];
|
||||||
|
this.props.openNextPanel({
|
||||||
|
index,
|
||||||
|
...tabToChange,
|
||||||
|
propPaneId: this.props.widgetProperties.widgetId,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const tabs: Array<{
|
const tabs: Array<{
|
||||||
id: string;
|
id: string;
|
||||||
label: string;
|
label: string;
|
||||||
}> = _.isString(this.props.propertyValue) ? [] : this.props.propertyValue;
|
}> = _.isString(this.props.propertyValue)
|
||||||
|
? []
|
||||||
|
: Object.values(this.props.propertyValue);
|
||||||
return (
|
return (
|
||||||
<TabsWrapper>
|
<TabsWrapper>
|
||||||
<DroppableComponent
|
<DroppableComponent
|
||||||
|
|
@ -167,6 +174,7 @@ class TabControl extends BaseControl<ControlProps> {
|
||||||
updateOption={this.updateOption}
|
updateOption={this.updateOption}
|
||||||
updateItems={this.updateItems}
|
updateItems={this.updateItems}
|
||||||
toggleVisibility={this.toggleVisibility}
|
toggleVisibility={this.toggleVisibility}
|
||||||
|
onEdit={this.onEdit}
|
||||||
/>
|
/>
|
||||||
<StyledPropertyPaneButtonWrapper>
|
<StyledPropertyPaneButtonWrapper>
|
||||||
<StyledPropertyPaneButton
|
<StyledPropertyPaneButton
|
||||||
|
|
@ -204,51 +212,52 @@ class TabControl extends BaseControl<ControlProps> {
|
||||||
};
|
};
|
||||||
|
|
||||||
deleteOption = (index: number) => {
|
deleteOption = (index: number) => {
|
||||||
let tabs: Array<Record<string, unknown>> = this.props.propertyValue.slice();
|
const tabsArray: any = Object.values(this.props.propertyValue);
|
||||||
if (tabs.length === 1) return;
|
const itemId = tabsArray[index].id;
|
||||||
delete tabs[index];
|
if (tabsArray && tabsArray.length === 1) return;
|
||||||
tabs = tabs.filter(Boolean);
|
const updatedArray = tabsArray.filter((eachItem: any, i: number) => {
|
||||||
this.updateProperty(this.props.propertyName, tabs);
|
return i !== index;
|
||||||
|
});
|
||||||
|
const updatedObj = updatedArray.reduce(
|
||||||
|
(obj: any, each: any, index: number) => {
|
||||||
|
obj[each.id] = {
|
||||||
|
...each,
|
||||||
|
index,
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
this.deleteProperties([`${this.props.propertyName}.${itemId}.isVisible`]);
|
||||||
|
this.updateProperty(this.props.propertyName, updatedObj);
|
||||||
};
|
};
|
||||||
|
|
||||||
updateOption = (index: number, updatedLabel: string) => {
|
updateOption = (index: number, updatedLabel: string) => {
|
||||||
const tabs: Array<{
|
const tabsArray: any = Object.values(this.props.propertyValue);
|
||||||
id: string;
|
const itemId = tabsArray[index].id;
|
||||||
label: string;
|
this.updateProperty(
|
||||||
}> = this.props.propertyValue;
|
`${this.props.propertyName}.${itemId}.label`,
|
||||||
const updatedTabs = tabs.map((tab, tabIndex) => {
|
updatedLabel,
|
||||||
if (index === tabIndex) {
|
);
|
||||||
return {
|
|
||||||
...tab,
|
|
||||||
label: updatedLabel,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return tab;
|
|
||||||
});
|
|
||||||
this.updateProperty(this.props.propertyName, updatedTabs);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
addOption = () => {
|
addOption = () => {
|
||||||
let tabs: Array<{
|
let tabs = this.props.propertyValue;
|
||||||
id: string;
|
const tabsArray = Object.values(tabs);
|
||||||
label: string;
|
|
||||||
widgetId: string;
|
|
||||||
isVisible: boolean;
|
|
||||||
}> = this.props.propertyValue;
|
|
||||||
const newTabId = generateReactKey({ prefix: "tab" });
|
const newTabId = generateReactKey({ prefix: "tab" });
|
||||||
const newTabLabel = getNextEntityName(
|
const newTabLabel = getNextEntityName(
|
||||||
"Tab ",
|
"Tab ",
|
||||||
tabs.map((tab) => tab.label),
|
tabsArray.map((tab: any) => tab.label),
|
||||||
);
|
);
|
||||||
tabs = [
|
tabs = {
|
||||||
...tabs,
|
...tabs,
|
||||||
{
|
[newTabId]: {
|
||||||
id: newTabId,
|
id: newTabId,
|
||||||
label: newTabLabel,
|
label: newTabLabel,
|
||||||
widgetId: generateReactKey(),
|
widgetId: generateReactKey(),
|
||||||
isVisible: true,
|
isVisible: true,
|
||||||
},
|
},
|
||||||
];
|
};
|
||||||
|
|
||||||
this.updateProperty(this.props.propertyName, tabs);
|
this.updateProperty(this.props.propertyName, tabs);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ const FIELD_VALUES: Record<
|
||||||
CANVAS_WIDGET: {},
|
CANVAS_WIDGET: {},
|
||||||
ICON_WIDGET: {},
|
ICON_WIDGET: {},
|
||||||
SKELETON_WIDGET: {},
|
SKELETON_WIDGET: {},
|
||||||
|
TABS_MIGRATOR_WIDGET: {},
|
||||||
CONTAINER_WIDGET: {
|
CONTAINER_WIDGET: {
|
||||||
backgroundColor: "string",
|
backgroundColor: "string",
|
||||||
isVisible: "boolean",
|
isVisible: "boolean",
|
||||||
|
|
@ -61,8 +62,6 @@ const FIELD_VALUES: Record<
|
||||||
// onSelectionChange: "Function Call",
|
// onSelectionChange: "Function Call",
|
||||||
},
|
},
|
||||||
TABS_WIDGET: {
|
TABS_WIDGET: {
|
||||||
tabs:
|
|
||||||
"Array<{ label: string, id: string(unique), widgetId: string(unique) }>",
|
|
||||||
selectedTab: "string",
|
selectedTab: "string",
|
||||||
isVisible: "boolean",
|
isVisible: "boolean",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,10 @@ export const HelpMap = {
|
||||||
path: "",
|
path: "",
|
||||||
searchKey: "Tabs",
|
searchKey: "Tabs",
|
||||||
},
|
},
|
||||||
|
TABS_MIGRATOR_WIDGET: {
|
||||||
|
path: "",
|
||||||
|
searchKey: "",
|
||||||
|
},
|
||||||
MODAL_WIDGET: {
|
MODAL_WIDGET: {
|
||||||
path: "",
|
path: "",
|
||||||
searchKey: "",
|
searchKey: "",
|
||||||
|
|
|
||||||
|
|
@ -340,6 +340,7 @@ export const ReduxActionTypes: { [key: string]: string } = {
|
||||||
UNDO_DELETE_WIDGET: "UNDO_DELETE_WIDGET",
|
UNDO_DELETE_WIDGET: "UNDO_DELETE_WIDGET",
|
||||||
CUT_SELECTED_WIDGET: "CUT_SELECTED_WIDGET",
|
CUT_SELECTED_WIDGET: "CUT_SELECTED_WIDGET",
|
||||||
WIDGET_ADD_CHILDREN: "WIDGET_ADD_CHILDREN",
|
WIDGET_ADD_CHILDREN: "WIDGET_ADD_CHILDREN",
|
||||||
|
WIDGET_UPDATE_PROPERTY: "WIDGET_UPDATE_PROPERTY",
|
||||||
SET_EVALUATED_TREE: "SET_EVALUATED_TREE",
|
SET_EVALUATED_TREE: "SET_EVALUATED_TREE",
|
||||||
SET_EVALUATION_INVERSE_DEPENDENCY_MAP:
|
SET_EVALUATION_INVERSE_DEPENDENCY_MAP:
|
||||||
"SET_EVALUATION_INVERSE_DEPENDENCY_MAP",
|
"SET_EVALUATION_INVERSE_DEPENDENCY_MAP",
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ export enum WidgetTypes {
|
||||||
SKELETON_WIDGET = "SKELETON_WIDGET",
|
SKELETON_WIDGET = "SKELETON_WIDGET",
|
||||||
LIST_WIDGET = "LIST_WIDGET",
|
LIST_WIDGET = "LIST_WIDGET",
|
||||||
SWITCH_WIDGET = "SWITCH_WIDGET",
|
SWITCH_WIDGET = "SWITCH_WIDGET",
|
||||||
|
TABS_MIGRATOR_WIDGET = "TABS_MIGRATOR_WIDGET",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type WidgetType = keyof typeof WidgetTypes;
|
export type WidgetType = keyof typeof WidgetTypes;
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ export enum VALIDATION_TYPES {
|
||||||
DEFAULT_DATE = "DEFAULT_DATE",
|
DEFAULT_DATE = "DEFAULT_DATE",
|
||||||
MIN_DATE = "MIN_DATE",
|
MIN_DATE = "MIN_DATE",
|
||||||
MAX_DATE = "MAX_DATE",
|
MAX_DATE = "MAX_DATE",
|
||||||
TABS_DATA = "TABS_DATA",
|
|
||||||
LIST_DATA = "LIST_DATA",
|
LIST_DATA = "LIST_DATA",
|
||||||
CHART_SERIES_DATA = "CHART_SERIES_DATA",
|
CHART_SERIES_DATA = "CHART_SERIES_DATA",
|
||||||
CUSTOM_FUSION_CHARTS_DATA = "CUSTOM_FUSION_CHARTS_DATA",
|
CUSTOM_FUSION_CHARTS_DATA = "CUSTOM_FUSION_CHARTS_DATA",
|
||||||
|
|
@ -30,6 +29,7 @@ export enum VALIDATION_TYPES {
|
||||||
LAT_LONG = "LAT_LONG",
|
LAT_LONG = "LAT_LONG",
|
||||||
TABLE_PAGE_NO = "TABLE_PAGE_NO",
|
TABLE_PAGE_NO = "TABLE_PAGE_NO",
|
||||||
ROW_INDICES = "ROW_INDICES",
|
ROW_INDICES = "ROW_INDICES",
|
||||||
|
TABS_DATA = "TABS_DATA",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ValidationResponse = {
|
export type ValidationResponse = {
|
||||||
|
|
@ -43,6 +43,7 @@ export type Validator = (
|
||||||
value: any,
|
value: any,
|
||||||
props: WidgetProps,
|
props: WidgetProps,
|
||||||
dataTree?: DataTree,
|
dataTree?: DataTree,
|
||||||
|
property?: string,
|
||||||
) => ValidationResponse;
|
) => ValidationResponse;
|
||||||
|
|
||||||
export const ISO_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.sssZ";
|
export const ISO_DATE_FORMAT = "YYYY-MM-DDTHH:mm:ss.sssZ";
|
||||||
|
|
|
||||||
|
|
@ -236,10 +236,22 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
columns: 8,
|
columns: 8,
|
||||||
shouldScrollContents: false,
|
shouldScrollContents: false,
|
||||||
widgetName: "Tabs",
|
widgetName: "Tabs",
|
||||||
tabs: [
|
tabsObj: {
|
||||||
{ label: "Tab 1", id: "tab1", widgetId: "", isVisible: true },
|
tab1: {
|
||||||
{ label: "Tab 2", id: "tab2", widgetId: "", isVisible: true },
|
label: "Tab 1",
|
||||||
],
|
id: "tab1",
|
||||||
|
widgetId: "",
|
||||||
|
isVisible: true,
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
tab2: {
|
||||||
|
label: "Tab 2",
|
||||||
|
id: "tab2",
|
||||||
|
widgetId: "",
|
||||||
|
isVisible: true,
|
||||||
|
index: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
shouldShowTabs: true,
|
shouldShowTabs: true,
|
||||||
defaultTab: "Tab 1",
|
defaultTab: "Tab 1",
|
||||||
blueprint: {
|
blueprint: {
|
||||||
|
|
@ -247,18 +259,18 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
{
|
{
|
||||||
type: BlueprintOperationTypes.MODIFY_PROPS,
|
type: BlueprintOperationTypes.MODIFY_PROPS,
|
||||||
fn: (widget: WidgetProps & { children?: WidgetProps[] }) => {
|
fn: (widget: WidgetProps & { children?: WidgetProps[] }) => {
|
||||||
const tabs = [...widget.tabs];
|
const tabs = Object.values({ ...widget.tabsObj });
|
||||||
|
const tabsObj = tabs.reduce((obj: any, tab: any) => {
|
||||||
const newTabs = tabs.map((tab: any) => {
|
|
||||||
const newTab = { ...tab };
|
const newTab = { ...tab };
|
||||||
newTab.widgetId = generateReactKey();
|
newTab.widgetId = generateReactKey();
|
||||||
return newTab;
|
obj[newTab.id] = newTab;
|
||||||
});
|
return obj;
|
||||||
|
}, {});
|
||||||
const updatePropertyMap = [
|
const updatePropertyMap = [
|
||||||
{
|
{
|
||||||
widgetId: widget.widgetId,
|
widgetId: widget.widgetId,
|
||||||
propertyName: "tabs",
|
propertyName: "tabsObj",
|
||||||
propertyValue: newTabs,
|
propertyValue: tabsObj,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
return updatePropertyMap;
|
return updatePropertyMap;
|
||||||
|
|
@ -266,7 +278,7 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
version: 1,
|
version: 2,
|
||||||
},
|
},
|
||||||
MODAL_WIDGET: {
|
MODAL_WIDGET: {
|
||||||
rows: 6,
|
rows: 6,
|
||||||
|
|
@ -511,6 +523,13 @@ const WidgetConfigResponse: WidgetConfigReducerState = {
|
||||||
widgetName: "Skeleton",
|
widgetName: "Skeleton",
|
||||||
version: 1,
|
version: 1,
|
||||||
},
|
},
|
||||||
|
TABS_MIGRATOR_WIDGET: {
|
||||||
|
isLoading: true,
|
||||||
|
rows: 1,
|
||||||
|
columns: 1,
|
||||||
|
widgetName: "Skeleton",
|
||||||
|
version: 1,
|
||||||
|
},
|
||||||
[WidgetTypes.LIST_WIDGET]: {
|
[WidgetTypes.LIST_WIDGET]: {
|
||||||
backgroundColor: "",
|
backgroundColor: "",
|
||||||
itemBackgroundColor: "white",
|
itemBackgroundColor: "white",
|
||||||
|
|
|
||||||
|
|
@ -68,7 +68,10 @@ export const CurrentPageEntityProperties = memo(
|
||||||
case ENTITY_TYPE.WIDGET:
|
case ENTITY_TYPE.WIDGET:
|
||||||
const type: Exclude<
|
const type: Exclude<
|
||||||
Partial<WidgetType>,
|
Partial<WidgetType>,
|
||||||
"CANVAS_WIDGET" | "ICON_WIDGET" | "SKELETON_WIDGET"
|
| "CANVAS_WIDGET"
|
||||||
|
| "ICON_WIDGET"
|
||||||
|
| "SKELETON_WIDGET"
|
||||||
|
| "TABS_MIGRATOR_WIDGET"
|
||||||
> = entity.type;
|
> = entity.type;
|
||||||
config = entityDefinitions[type];
|
config = entityDefinitions[type];
|
||||||
if (!config) {
|
if (!config) {
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,10 @@ export const EntityProperties = memo(
|
||||||
case ENTITY_TYPE.WIDGET:
|
case ENTITY_TYPE.WIDGET:
|
||||||
const type: Exclude<
|
const type: Exclude<
|
||||||
Partial<WidgetType>,
|
Partial<WidgetType>,
|
||||||
"CANVAS_WIDGET" | "ICON_WIDGET" | "SKELETON_WIDGET"
|
| "CANVAS_WIDGET"
|
||||||
|
| "ICON_WIDGET"
|
||||||
|
| "SKELETON_WIDGET"
|
||||||
|
| "TABS_MIGRATOR_WIDGET"
|
||||||
> = entity.type;
|
> = entity.type;
|
||||||
config = entityDefinitions[type];
|
config = entityDefinitions[type];
|
||||||
if (!config) {
|
if (!config) {
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ export const EntityName = forwardRef(
|
||||||
) {
|
) {
|
||||||
const parent = state.entities.canvasWidgets[widget.parentId];
|
const parent = state.entities.canvasWidgets[widget.parentId];
|
||||||
if (parent.type === WidgetTypes.TABS_WIDGET) {
|
if (parent.type === WidgetTypes.TABS_WIDGET) {
|
||||||
return parent.tabs;
|
return Object.values(parent.tabsObj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,15 @@ export const WidgetContextMenu = (props: {
|
||||||
// If the widget is a tab we are updating the `tabs` of the property of the widget
|
// If the widget is a tab we are updating the `tabs` of the property of the widget
|
||||||
// This is similar to deleting a tab from the property pane
|
// This is similar to deleting a tab from the property pane
|
||||||
if (widget.tabName && parentWidget.type === WidgetTypes.TABS_WIDGET) {
|
if (widget.tabName && parentWidget.type === WidgetTypes.TABS_WIDGET) {
|
||||||
const filteredTabs = parentWidget.tabs.filter(
|
const tabsObj = { ...parentWidget.tabsObj };
|
||||||
(tab: any) => tab.widgetId !== widgetId,
|
delete tabsObj[widget.tabId];
|
||||||
);
|
const filteredTabs = Object.values(tabsObj);
|
||||||
|
|
||||||
if (widget.parentId && !!filteredTabs.length) {
|
if (widget.parentId && !!filteredTabs.length) {
|
||||||
dispatch(
|
dispatch(
|
||||||
updateWidgetPropertyRequest(
|
updateWidgetPropertyRequest(
|
||||||
widget.parentId,
|
widget.parentId,
|
||||||
"tabs",
|
"tabsObj",
|
||||||
filteredTabs,
|
tabsObj,
|
||||||
RenderModes.CANVAS,
|
RenderModes.CANVAS,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ export const PanelPropertiesEditor = (
|
||||||
}, [widgetProperties, panelParentPropertyPath, panelProps, panelConfig]);
|
}, [widgetProperties, panelParentPropertyPath, panelProps, panelConfig]);
|
||||||
|
|
||||||
const panelConfigs = useMemo(() => {
|
const panelConfigs = useMemo(() => {
|
||||||
if (currentIndex) {
|
if (currentIndex !== undefined) {
|
||||||
let path: string | undefined = undefined;
|
let path: string | undefined = undefined;
|
||||||
if (isString(currentIndex)) {
|
if (isString(currentIndex)) {
|
||||||
path = `${panelParentPropertyPath}.${currentIndex}`;
|
path = `${panelParentPropertyPath}.${currentIndex}`;
|
||||||
|
|
@ -147,7 +147,7 @@ export const PanelPropertiesEditor = (
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (panelProps.widgetId !== widgetProperties.widgetId) {
|
if (panelProps.propPaneId !== widgetProperties.widgetId) {
|
||||||
props.closePanel();
|
props.closePanel();
|
||||||
}
|
}
|
||||||
}, [widgetProperties.widgetId]);
|
}, [widgetProperties.widgetId]);
|
||||||
|
|
|
||||||
|
|
@ -249,12 +249,13 @@ const PropertyControl = memo((props: Props) => {
|
||||||
let validationMessage = "";
|
let validationMessage = "";
|
||||||
if (widgetProperties) {
|
if (widgetProperties) {
|
||||||
isValid = widgetProperties.invalidProps
|
isValid = widgetProperties.invalidProps
|
||||||
? !(propertyName in widgetProperties.invalidProps)
|
? !_.has(widgetProperties.invalidProps, propertyName)
|
||||||
: true;
|
: true;
|
||||||
validationMessage = widgetProperties.validationMessages
|
const validationMsgPresent =
|
||||||
? propertyName in widgetProperties.validationMessages
|
widgetProperties.validationMessages &&
|
||||||
? widgetProperties.validationMessages[propertyName]
|
_.has(widgetProperties.validationMessages, propertyName);
|
||||||
: ""
|
validationMessage = validationMsgPresent
|
||||||
|
? _.get(widgetProperties.validationMessages, propertyName)
|
||||||
: "";
|
: "";
|
||||||
}
|
}
|
||||||
return { isValid, validationMessage };
|
return { isValid, validationMessage };
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import { FilePickerWidgetProps } from "../../widgets/FilepickerWidget";
|
||||||
import {
|
import {
|
||||||
TabsWidgetProps,
|
TabsWidgetProps,
|
||||||
TabContainerWidgetProps,
|
TabContainerWidgetProps,
|
||||||
} from "../../widgets/TabsWidget";
|
} from "../../widgets/Tabs/TabsWidget";
|
||||||
import { ChartWidgetProps } from "widgets/ChartWidget";
|
import { ChartWidgetProps } from "widgets/ChartWidget";
|
||||||
import { FormWidgetProps } from "widgets/FormWidget";
|
import { FormWidgetProps } from "widgets/FormWidget";
|
||||||
import { FormButtonWidgetProps } from "widgets/FormButtonWidget";
|
import { FormButtonWidgetProps } from "widgets/FormButtonWidget";
|
||||||
|
|
@ -70,6 +70,8 @@ export interface WidgetConfigReducerState {
|
||||||
FILE_PICKER_WIDGET: Partial<FilePickerWidgetProps> & WidgetConfigProps;
|
FILE_PICKER_WIDGET: Partial<FilePickerWidgetProps> & WidgetConfigProps;
|
||||||
TABS_WIDGET: Partial<TabsWidgetProps<TabContainerWidgetProps>> &
|
TABS_WIDGET: Partial<TabsWidgetProps<TabContainerWidgetProps>> &
|
||||||
WidgetConfigProps;
|
WidgetConfigProps;
|
||||||
|
TABS_MIGRATOR_WIDGET: Partial<TabsWidgetProps<TabContainerWidgetProps>> &
|
||||||
|
WidgetConfigProps;
|
||||||
MODAL_WIDGET: Partial<ModalWidgetProps> & WidgetConfigProps;
|
MODAL_WIDGET: Partial<ModalWidgetProps> & WidgetConfigProps;
|
||||||
CHART_WIDGET: Partial<ChartWidgetProps> & WidgetConfigProps;
|
CHART_WIDGET: Partial<ChartWidgetProps> & WidgetConfigProps;
|
||||||
FORM_WIDGET: Partial<FormWidgetProps> & WidgetConfigProps;
|
FORM_WIDGET: Partial<FormWidgetProps> & WidgetConfigProps;
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ export function* fetchPageListSaga(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getCanvasWidgetsPayload = (
|
export const getCanvasWidgetsPayload = (
|
||||||
pageResponse: FetchPageResponse,
|
pageResponse: FetchPageResponse,
|
||||||
): UpdateCanvasPayload => {
|
): UpdateCanvasPayload => {
|
||||||
const normalizedResponse = CanvasWidgetsNormalizer.normalize(
|
const normalizedResponse = CanvasWidgetsNormalizer.normalize(
|
||||||
|
|
@ -596,13 +596,14 @@ export function* updateWidgetNameSaga(
|
||||||
|
|
||||||
// TODO(abhinav): Why do we need to jump through these hoops just to
|
// TODO(abhinav): Why do we need to jump through these hoops just to
|
||||||
// change the tab name? Figure out a better design to make this moot.
|
// change the tab name? Figure out a better design to make this moot.
|
||||||
const tabs:
|
const tabsObj: Record<
|
||||||
| Array<{
|
string,
|
||||||
|
{
|
||||||
id: string;
|
id: string;
|
||||||
widgetId: string;
|
widgetId: string;
|
||||||
label: string;
|
label: string;
|
||||||
}>
|
}
|
||||||
| undefined = yield select((state: AppState) => {
|
> = yield select((state: AppState) => {
|
||||||
// Check if this widget exists in the canvas widgets
|
// Check if this widget exists in the canvas widgets
|
||||||
if (state.entities.canvasWidgets.hasOwnProperty(action.payload.id)) {
|
if (state.entities.canvasWidgets.hasOwnProperty(action.payload.id)) {
|
||||||
// If it does assign it to a variable
|
// If it does assign it to a variable
|
||||||
|
|
@ -617,7 +618,7 @@ export function* updateWidgetNameSaga(
|
||||||
// Check if this parent is a TABS_WIDGET
|
// Check if this parent is a TABS_WIDGET
|
||||||
if (parent.type === WidgetTypes.TABS_WIDGET) {
|
if (parent.type === WidgetTypes.TABS_WIDGET) {
|
||||||
// If it is return the tabs property
|
// If it is return the tabs property
|
||||||
return parent.tabs;
|
return parent.tabsObj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -626,7 +627,8 @@ export function* updateWidgetNameSaga(
|
||||||
});
|
});
|
||||||
|
|
||||||
// If we're trying to update the name of a tab in the TABS_WIDGET
|
// If we're trying to update the name of a tab in the TABS_WIDGET
|
||||||
if (tabs !== undefined) {
|
if (tabsObj !== undefined) {
|
||||||
|
const tabs: any = Object.values(tabsObj);
|
||||||
// Get all canvas widgets
|
// Get all canvas widgets
|
||||||
const stateWidgets = yield select(getWidgets);
|
const stateWidgets = yield select(getWidgets);
|
||||||
// Shallow copy canvas widgets as they're immutable
|
// Shallow copy canvas widgets as they're immutable
|
||||||
|
|
@ -641,14 +643,19 @@ export function* updateWidgetNameSaga(
|
||||||
// Shallow copy the parent widget so that we can update the properties
|
// Shallow copy the parent widget so that we can update the properties
|
||||||
const parent = { ...widgets[parentId] };
|
const parent = { ...widgets[parentId] };
|
||||||
// Update the tabs property of the parent tabs widget
|
// Update the tabs property of the parent tabs widget
|
||||||
parent.tabs = tabs.map(
|
const tabToChange = tabs.find(
|
||||||
(tab: { widgetId: string; label: string; id: string }) => {
|
(each: any) => each.widgetId === action.payload.id,
|
||||||
if (tab.widgetId === action.payload.id) {
|
|
||||||
return { ...tab, label: action.payload.newName };
|
|
||||||
}
|
|
||||||
return tab;
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
const updatedTab = {
|
||||||
|
...tabToChange,
|
||||||
|
label: action.payload.newName,
|
||||||
|
};
|
||||||
|
parent.tabsObj = {
|
||||||
|
...parent.tabsObj,
|
||||||
|
[updatedTab.id]: {
|
||||||
|
...updatedTab,
|
||||||
|
},
|
||||||
|
};
|
||||||
// replace the parent widget in the canvas widgets
|
// replace the parent widget in the canvas widgets
|
||||||
widgets[parentId] = parent;
|
widgets[parentId] = parent;
|
||||||
// Update and save the new widgets
|
// Update and save the new widgets
|
||||||
|
|
|
||||||
|
|
@ -593,20 +593,21 @@ export function* undoDeleteSaga(action: ReduxAction<{ widgetId: string }>) {
|
||||||
widget.type === WidgetTypes.CANVAS_WIDGET &&
|
widget.type === WidgetTypes.CANVAS_WIDGET &&
|
||||||
widget.parentId
|
widget.parentId
|
||||||
) {
|
) {
|
||||||
const parent = { ...widgets[widget.parentId] };
|
const parent = cloneDeep(widgets[widget.parentId]);
|
||||||
if (parent.tabs) {
|
if (parent.tabsObj) {
|
||||||
parent.tabs = parent.tabs.slice();
|
|
||||||
try {
|
try {
|
||||||
parent.tabs.push({
|
const tabs = Object.values(parent.tabsObj);
|
||||||
|
parent.tabsObj[widget.tabId] = {
|
||||||
id: widget.tabId,
|
id: widget.tabId,
|
||||||
widgetId: widget.widgetId,
|
widgetId: widget.widgetId,
|
||||||
label: widget.tabName || widget.widgetName,
|
label: widget.tabName || widget.widgetName,
|
||||||
});
|
isVisible: true,
|
||||||
|
};
|
||||||
widgets = {
|
widgets = {
|
||||||
...widgets,
|
...widgets,
|
||||||
[widget.parentId]: {
|
[widget.parentId]: {
|
||||||
...widgets[widget.parentId],
|
...widgets[widget.parentId],
|
||||||
tabs: parent.tabs,
|
tabsObj: parent.tabsObj,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -866,7 +867,7 @@ function* setWidgetDynamicPropertySaga(
|
||||||
) {
|
) {
|
||||||
const { isDynamic, propertyPath, widgetId } = action.payload;
|
const { isDynamic, propertyPath, widgetId } = action.payload;
|
||||||
const stateWidget: WidgetProps = yield select(getWidget, widgetId);
|
const stateWidget: WidgetProps = yield select(getWidget, widgetId);
|
||||||
let widget = { ...stateWidget };
|
let widget = cloneDeep({ ...stateWidget });
|
||||||
const propertyValue = _.get(widget, propertyPath);
|
const propertyValue = _.get(widget, propertyPath);
|
||||||
let dynamicPropertyPathList = getWidgetDynamicPropertyPathList(widget);
|
let dynamicPropertyPathList = getWidgetDynamicPropertyPathList(widget);
|
||||||
if (isDynamic) {
|
if (isDynamic) {
|
||||||
|
|
@ -1041,6 +1042,9 @@ function* removeWidgetProperties(widget: WidgetProps, paths: string[]) {
|
||||||
let dynamicBindingPathList: DynamicPath[] = getEntityDynamicBindingPathList(
|
let dynamicBindingPathList: DynamicPath[] = getEntityDynamicBindingPathList(
|
||||||
widget,
|
widget,
|
||||||
);
|
);
|
||||||
|
let dynamicPropertyPathList: DynamicPath[] = getWidgetDynamicPropertyPathList(
|
||||||
|
widget,
|
||||||
|
);
|
||||||
|
|
||||||
paths.forEach((propertyPath) => {
|
paths.forEach((propertyPath) => {
|
||||||
dynamicTriggerPathList = dynamicTriggerPathList.filter((dynamicPath) => {
|
dynamicTriggerPathList = dynamicTriggerPathList.filter((dynamicPath) => {
|
||||||
|
|
@ -1050,10 +1054,18 @@ function* removeWidgetProperties(widget: WidgetProps, paths: string[]) {
|
||||||
dynamicBindingPathList = dynamicBindingPathList.filter((dynamicPath) => {
|
dynamicBindingPathList = dynamicBindingPathList.filter((dynamicPath) => {
|
||||||
return !isChildPropertyPath(propertyPath, dynamicPath.key);
|
return !isChildPropertyPath(propertyPath, dynamicPath.key);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dynamicPropertyPathList = dynamicPropertyPathList.filter(
|
||||||
|
(dynamicPath) => {
|
||||||
|
return !isChildPropertyPath(propertyPath, dynamicPath.key);
|
||||||
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
widget.dynamicBindingPathList = dynamicBindingPathList;
|
widget.dynamicBindingPathList = dynamicBindingPathList;
|
||||||
widget.dynamicTriggerPathList = dynamicTriggerPathList;
|
widget.dynamicTriggerPathList = dynamicTriggerPathList;
|
||||||
|
widget.dynamicPropertyPathList = dynamicPropertyPathList;
|
||||||
|
|
||||||
paths.forEach((propertyPath) => {
|
paths.forEach((propertyPath) => {
|
||||||
widget = unsetPropertyPath(widget, propertyPath) as WidgetProps;
|
widget = unsetPropertyPath(widget, propertyPath) as WidgetProps;
|
||||||
});
|
});
|
||||||
|
|
@ -1389,14 +1401,15 @@ function* pasteWidgetSaga() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the tabs for the tabs widget.
|
// Update the tabs for the tabs widget.
|
||||||
if (widget.tabs && widget.type === WidgetTypes.TABS_WIDGET) {
|
if (widget.tabsObj && widget.type === WidgetTypes.TABS_WIDGET) {
|
||||||
try {
|
try {
|
||||||
const tabs = widget.tabs;
|
const tabs = Object.values(widget.tabsObj);
|
||||||
if (Array.isArray(tabs)) {
|
if (Array.isArray(tabs)) {
|
||||||
widget.tabs = tabs.map((tab) => {
|
widget.tabsObj = tabs.reduce((obj: any, tab) => {
|
||||||
tab.widgetId = widgetIdMap[tab.widgetId];
|
tab.widgetId = widgetIdMap[tab.widgetId];
|
||||||
return tab;
|
obj[tab.id] = tab;
|
||||||
});
|
return obj;
|
||||||
|
}, {});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.debug("Error updating tabs", error);
|
log.debug("Error updating tabs", error);
|
||||||
|
|
@ -1692,6 +1705,10 @@ export default function* widgetOperationSagas() {
|
||||||
ReduxActionTypes.UPDATE_WIDGET_PROPERTY_REQUEST,
|
ReduxActionTypes.UPDATE_WIDGET_PROPERTY_REQUEST,
|
||||||
updateWidgetPropertySaga,
|
updateWidgetPropertySaga,
|
||||||
),
|
),
|
||||||
|
takeEvery(
|
||||||
|
ReduxActionTypes.WIDGET_UPDATE_PROPERTY,
|
||||||
|
updateWidgetPropertySaga,
|
||||||
|
),
|
||||||
takeEvery(
|
takeEvery(
|
||||||
ReduxActionTypes.SET_WIDGET_DYNAMIC_PROPERTY,
|
ReduxActionTypes.SET_WIDGET_DYNAMIC_PROPERTY,
|
||||||
setWidgetDynamicPropertySaga,
|
setWidgetDynamicPropertySaga,
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,12 @@ export const getWidgetPropsForPropertyPane = createSelector(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const isResizingorDragging = (state: AppState) =>
|
||||||
|
state.ui.widgetDragResize.isResizing || state.ui.widgetDragResize.isDragging;
|
||||||
|
|
||||||
export const getIsPropertyPaneVisible = createSelector(
|
export const getIsPropertyPaneVisible = createSelector(
|
||||||
getPropertyPaneState,
|
getPropertyPaneState,
|
||||||
(pane: PropertyPaneReduxState) => !!(pane.isVisible && pane.widgetId),
|
isResizingorDragging,
|
||||||
|
(pane: PropertyPaneReduxState, isResizingorDragging: boolean) =>
|
||||||
|
!!(!isResizingorDragging && pane.isVisible && pane.widgetId),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import { migrateIncorrectDynamicBindingPathLists } from "utils/migrations/Incorr
|
||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
import { migrateTextStyleFromTextWidget } from "./migrations/TextWidgetReplaceTextStyle";
|
import { migrateTextStyleFromTextWidget } from "./migrations/TextWidgetReplaceTextStyle";
|
||||||
import { nextAvailableRowInContainer } from "entities/Widget/utils";
|
import { nextAvailableRowInContainer } from "entities/Widget/utils";
|
||||||
|
import { DATA_BIND_REGEX_GLOBAL } from "constants/BindingsConstants";
|
||||||
|
|
||||||
export type WidgetOperationParams = {
|
export type WidgetOperationParams = {
|
||||||
operation: WidgetOperation;
|
operation: WidgetOperation;
|
||||||
|
|
@ -333,6 +334,111 @@ const rteDefaultValueMigration = (
|
||||||
return currentDSL;
|
return currentDSL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function migrateTabsDataUsingMigrator(
|
||||||
|
currentDSL: ContainerWidgetProps<WidgetProps>,
|
||||||
|
) {
|
||||||
|
if (currentDSL.type === WidgetTypes.TABS_WIDGET && currentDSL.version === 1) {
|
||||||
|
try {
|
||||||
|
currentDSL.type = WidgetTypes.TABS_MIGRATOR_WIDGET;
|
||||||
|
currentDSL.version = 1;
|
||||||
|
} catch (error) {
|
||||||
|
Sentry.captureException({
|
||||||
|
message: "Tabs Migration Failed",
|
||||||
|
oldData: currentDSL.tabs,
|
||||||
|
});
|
||||||
|
currentDSL.tabsObj = {};
|
||||||
|
delete currentDSL.tabs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentDSL.children && currentDSL.children.length) {
|
||||||
|
currentDSL.children = currentDSL.children.map(migrateTabsDataUsingMigrator);
|
||||||
|
}
|
||||||
|
return currentDSL;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function migrateTabsData(currentDSL: ContainerWidgetProps<WidgetProps>) {
|
||||||
|
if (
|
||||||
|
[WidgetTypes.TABS_WIDGET, WidgetTypes.TABS_MIGRATOR_WIDGET].includes(
|
||||||
|
currentDSL.type as any,
|
||||||
|
) &&
|
||||||
|
currentDSL.version === 1
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
currentDSL.type = WidgetTypes.TABS_WIDGET;
|
||||||
|
const isTabsDataBinded = isString(currentDSL.tabs);
|
||||||
|
currentDSL.dynamicPropertyPathList =
|
||||||
|
currentDSL.dynamicPropertyPathList || [];
|
||||||
|
currentDSL.dynamicBindingPathList =
|
||||||
|
currentDSL.dynamicBindingPathList || [];
|
||||||
|
|
||||||
|
if (isTabsDataBinded) {
|
||||||
|
const tabsString = currentDSL.tabs.replace(
|
||||||
|
DATA_BIND_REGEX_GLOBAL,
|
||||||
|
(word: any) => `"${word}"`,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
currentDSL.tabs = JSON.parse(tabsString);
|
||||||
|
} catch (error) {
|
||||||
|
return migrateTabsDataUsingMigrator(currentDSL);
|
||||||
|
}
|
||||||
|
const dynamicPropsList = currentDSL.tabs
|
||||||
|
.filter((each: any) => DATA_BIND_REGEX_GLOBAL.test(each.isVisible))
|
||||||
|
.map((each: any) => {
|
||||||
|
return { key: `tabsObj.${each.id}.isVisible` };
|
||||||
|
});
|
||||||
|
const dynamicBindablePropsList = currentDSL.tabs.map((each: any) => {
|
||||||
|
return { key: `tabsObj.${each.id}.isVisible` };
|
||||||
|
});
|
||||||
|
currentDSL.dynamicPropertyPathList = [
|
||||||
|
...currentDSL.dynamicPropertyPathList,
|
||||||
|
...dynamicPropsList,
|
||||||
|
];
|
||||||
|
currentDSL.dynamicBindingPathList = [
|
||||||
|
...currentDSL.dynamicBindingPathList,
|
||||||
|
...dynamicBindablePropsList,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
currentDSL.dynamicPropertyPathList = currentDSL.dynamicPropertyPathList.filter(
|
||||||
|
(each) => {
|
||||||
|
return each.key !== "tabs";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
currentDSL.dynamicBindingPathList = currentDSL.dynamicBindingPathList.filter(
|
||||||
|
(each) => {
|
||||||
|
return each.key !== "tabs";
|
||||||
|
},
|
||||||
|
);
|
||||||
|
currentDSL.tabsObj = currentDSL.tabs.reduce(
|
||||||
|
(obj: any, tab: any, index: number) => {
|
||||||
|
obj = {
|
||||||
|
...obj,
|
||||||
|
[tab.id]: {
|
||||||
|
...tab,
|
||||||
|
isVisible: tab.isVisible === undefined ? true : tab.isVisible,
|
||||||
|
index,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
currentDSL.version = 2;
|
||||||
|
delete currentDSL.tabs;
|
||||||
|
} catch (error) {
|
||||||
|
Sentry.captureException({
|
||||||
|
message: "Tabs Migration Failed",
|
||||||
|
oldData: currentDSL.tabs,
|
||||||
|
});
|
||||||
|
currentDSL.tabsObj = {};
|
||||||
|
delete currentDSL.tabs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (currentDSL.children && currentDSL.children.length) {
|
||||||
|
currentDSL.children = currentDSL.children.map(migrateTabsData);
|
||||||
|
}
|
||||||
|
return currentDSL;
|
||||||
|
}
|
||||||
|
|
||||||
// A rudimentary transform function which updates the DSL based on its version.
|
// A rudimentary transform function which updates the DSL based on its version.
|
||||||
function migrateOldChartData(currentDSL: ContainerWidgetProps<WidgetProps>) {
|
function migrateOldChartData(currentDSL: ContainerWidgetProps<WidgetProps>) {
|
||||||
if (currentDSL.type === WidgetTypes.CHART_WIDGET) {
|
if (currentDSL.type === WidgetTypes.CHART_WIDGET) {
|
||||||
|
|
@ -543,6 +649,11 @@ const transformDSL = (currentDSL: ContainerWidgetProps<WidgetProps>) => {
|
||||||
currentDSL.version = 17;
|
currentDSL.version = 17;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (currentDSL.version === 17) {
|
||||||
|
currentDSL = migrateTabsData(currentDSL);
|
||||||
|
currentDSL.version = 18;
|
||||||
|
}
|
||||||
|
|
||||||
return currentDSL;
|
return currentDSL;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ import TabsWidget, {
|
||||||
TabsWidgetProps,
|
TabsWidgetProps,
|
||||||
TabContainerWidgetProps,
|
TabContainerWidgetProps,
|
||||||
ProfiledTabsWidget,
|
ProfiledTabsWidget,
|
||||||
} from "widgets/TabsWidget";
|
} from "widgets/Tabs/TabsWidget";
|
||||||
import {
|
import {
|
||||||
ModalWidgetProps,
|
ModalWidgetProps,
|
||||||
ProfiledModalWidget,
|
ProfiledModalWidget,
|
||||||
|
|
@ -100,6 +100,9 @@ import SwitchWidget, {
|
||||||
ProfiledSwitchWidget,
|
ProfiledSwitchWidget,
|
||||||
SwitchWidgetProps,
|
SwitchWidgetProps,
|
||||||
} from "widgets/SwitchWidget";
|
} from "widgets/SwitchWidget";
|
||||||
|
import TabsMigratorWidget, {
|
||||||
|
ProfiledTabsMigratorWidget,
|
||||||
|
} from "widgets/Tabs/TabsMigrator";
|
||||||
export default class WidgetBuilderRegistry {
|
export default class WidgetBuilderRegistry {
|
||||||
static registerWidgetBuilders() {
|
static registerWidgetBuilders() {
|
||||||
WidgetFactory.registerWidgetBuilder(
|
WidgetFactory.registerWidgetBuilder(
|
||||||
|
|
@ -296,6 +299,20 @@ export default class WidgetBuilderRegistry {
|
||||||
TabsWidget.getMetaPropertiesMap(),
|
TabsWidget.getMetaPropertiesMap(),
|
||||||
TabsWidget.getPropertyPaneConfig(),
|
TabsWidget.getPropertyPaneConfig(),
|
||||||
);
|
);
|
||||||
|
WidgetFactory.registerWidgetBuilder(
|
||||||
|
"TABS_MIGRATOR_WIDGET",
|
||||||
|
{
|
||||||
|
buildWidget(
|
||||||
|
widgetProps: TabsWidgetProps<TabContainerWidgetProps>,
|
||||||
|
): JSX.Element {
|
||||||
|
return <ProfiledTabsMigratorWidget {...widgetProps} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TabsMigratorWidget.getDerivedPropertiesMap(),
|
||||||
|
TabsMigratorWidget.getDefaultPropertiesMap(),
|
||||||
|
TabsMigratorWidget.getMetaPropertiesMap(),
|
||||||
|
TabsMigratorWidget.getPropertyPaneConfig(),
|
||||||
|
);
|
||||||
WidgetFactory.registerWidgetBuilder(
|
WidgetFactory.registerWidgetBuilder(
|
||||||
WidgetTypes.MODAL_WIDGET,
|
WidgetTypes.MODAL_WIDGET,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -170,7 +170,6 @@ export const entityDefinitions = {
|
||||||
},
|
},
|
||||||
TABS_WIDGET: {
|
TABS_WIDGET: {
|
||||||
isVisible: isVisible,
|
isVisible: isVisible,
|
||||||
tabs: "[tabs]",
|
|
||||||
selectedTab: "string",
|
selectedTab: "string",
|
||||||
},
|
},
|
||||||
MODAL_WIDGET: {
|
MODAL_WIDGET: {
|
||||||
|
|
|
||||||
110
app/client/src/widgets/Tabs/TabsMigrator.tsx
Normal file
110
app/client/src/widgets/Tabs/TabsMigrator.tsx
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
import BaseWidget, { WidgetState } from "widgets/BaseWidget";
|
||||||
|
import { TabContainerWidgetProps, TabsWidgetProps } from "./TabsWidget";
|
||||||
|
import React from "react";
|
||||||
|
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
|
||||||
|
import withMeta from "widgets/MetaHOC";
|
||||||
|
import * as Sentry from "@sentry/react";
|
||||||
|
import { migrateTabsData } from "utils/WidgetPropsUtils";
|
||||||
|
import { cloneDeep } from "lodash";
|
||||||
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
|
|
||||||
|
class TabsMigratorWidget extends BaseWidget<
|
||||||
|
TabsWidgetProps<TabContainerWidgetProps>,
|
||||||
|
WidgetState
|
||||||
|
> {
|
||||||
|
getPageView() {
|
||||||
|
return <></>;
|
||||||
|
}
|
||||||
|
static getPropertyPaneConfig() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
sectionName: "General",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
helpText: "Takes an array of tab names to render tabs",
|
||||||
|
propertyName: "tabs",
|
||||||
|
isJSConvertible: true,
|
||||||
|
label: "Tabs",
|
||||||
|
controlType: "TABS_INPUT",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: VALIDATION_TYPES.TABS_DATA,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "shouldShowTabs",
|
||||||
|
helpText:
|
||||||
|
"Hides the tabs so that different widgets can be displayed based on the default tab",
|
||||||
|
label: "Show Tabs",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "defaultTab",
|
||||||
|
helpText: "Selects a tab name specified by default",
|
||||||
|
placeholderText: "Enter tab name",
|
||||||
|
label: "Default Tab",
|
||||||
|
controlType: "INPUT_TEXT",
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: VALIDATION_TYPES.SELECTED_TAB,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "shouldScrollContents",
|
||||||
|
label: "Scroll Contents",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
propertyName: "isVisible",
|
||||||
|
label: "Visible",
|
||||||
|
helpText: "Controls the visibility of the widget",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
validation: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
sectionName: "Actions",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
helpText: "Triggers an action when the button is clicked",
|
||||||
|
propertyName: "onTabSelected",
|
||||||
|
label: "onTabSelected",
|
||||||
|
controlType: "ACTION_SELECTOR",
|
||||||
|
isJSConvertible: true,
|
||||||
|
isBindProperty: true,
|
||||||
|
isTriggerProperty: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.props.evaluatedValues) {
|
||||||
|
const tabsDsl = cloneDeep(this.props);
|
||||||
|
const migratedTabsDsl = migrateTabsData(tabsDsl);
|
||||||
|
this.batchUpdateWidgetProperty({
|
||||||
|
modify: {
|
||||||
|
tabsObj: migratedTabsDsl.tabsObj,
|
||||||
|
type: WidgetTypes.TABS_WIDGET,
|
||||||
|
version: 2,
|
||||||
|
dynamicPropertyPathList: migratedTabsDsl.dynamicPropertyPathList,
|
||||||
|
dynamicBindingPathList: migratedTabsDsl.dynamicBindingPathList,
|
||||||
|
},
|
||||||
|
remove: ["tabs"],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
getWidgetType(): WidgetType {
|
||||||
|
return "TABS_MIGRATOR_WIDGET";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default TabsMigratorWidget;
|
||||||
|
export const ProfiledTabsMigratorWidget = Sentry.withProfiler(
|
||||||
|
withMeta(TabsMigratorWidget),
|
||||||
|
);
|
||||||
98
app/client/src/widgets/Tabs/TabsWidget.test.tsx
Normal file
98
app/client/src/widgets/Tabs/TabsWidget.test.tsx
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
import {
|
||||||
|
buildChildren,
|
||||||
|
widgetCanvasFactory,
|
||||||
|
} from "test/factories/WidgetFactoryUtils";
|
||||||
|
import { render, fireEvent } from "test/testUtils";
|
||||||
|
|
||||||
|
import Canvas from "pages/Editor/Canvas";
|
||||||
|
import React from "react";
|
||||||
|
import { useDispatch } from "react-redux";
|
||||||
|
import { editorInitializer } from "utils/EditorUtils";
|
||||||
|
import { initCanvasLayout } from "actions/pageActions";
|
||||||
|
import { getCanvasWidgetsPayload } from "sagas/PageSagas";
|
||||||
|
import { noop } from "utils/AppsmithUtils";
|
||||||
|
|
||||||
|
Element.prototype.scrollTo = noop;
|
||||||
|
const SetCanvas = ({ dsl, children }: any) => {
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const mockResp: any = {
|
||||||
|
data: {
|
||||||
|
id: "asa",
|
||||||
|
name: "App",
|
||||||
|
applicationId: "asa",
|
||||||
|
layouts: [
|
||||||
|
{
|
||||||
|
id: "w323",
|
||||||
|
dsl,
|
||||||
|
layoutOnLoadActions: [],
|
||||||
|
layoutActions: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const canvasWidgetsPayload = getCanvasWidgetsPayload(mockResp);
|
||||||
|
dispatch(initCanvasLayout(canvasWidgetsPayload));
|
||||||
|
return <>{children}</>;
|
||||||
|
};
|
||||||
|
describe("Tabs widget functional cases", () => {
|
||||||
|
it("Should render 2 tabs by default", () => {
|
||||||
|
editorInitializer();
|
||||||
|
const children: any = buildChildren([{ type: "TABS_WIDGET" }]);
|
||||||
|
const dsl: any = widgetCanvasFactory.build({
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
const component = render(
|
||||||
|
<SetCanvas dsl={dsl}>
|
||||||
|
<Canvas dsl={dsl}></Canvas>
|
||||||
|
</SetCanvas>,
|
||||||
|
);
|
||||||
|
const tab1 = component.queryByText("Tab 1");
|
||||||
|
const tab2 = component.queryByText("Tab 2");
|
||||||
|
expect(tab1).toBeDefined();
|
||||||
|
expect(tab2).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Should render components inside tabs by default", () => {
|
||||||
|
editorInitializer();
|
||||||
|
const tab1Children = buildChildren([
|
||||||
|
{ type: "SWITCH_WIDGET", label: "Tab1 Switch" },
|
||||||
|
{ type: "CHECKBOX_WIDGET", label: "Tab1 Checkbox" },
|
||||||
|
]);
|
||||||
|
const tab2Children = buildChildren([
|
||||||
|
{ type: "INPUT_WIDGET", text: "Tab2 Text" },
|
||||||
|
{ type: "BUTTON_WIDGET", label: "Tab2 Button" },
|
||||||
|
]);
|
||||||
|
const children: any = buildChildren([{ type: "TABS_WIDGET" }]);
|
||||||
|
children[0].children[0].children = tab1Children;
|
||||||
|
children[0].children[1].children = tab2Children;
|
||||||
|
const dsl: any = widgetCanvasFactory.build({
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
const component = render(
|
||||||
|
<SetCanvas dsl={dsl}>
|
||||||
|
<Canvas dsl={dsl}></Canvas>
|
||||||
|
</SetCanvas>,
|
||||||
|
);
|
||||||
|
const tab1 = component.queryByText("Tab 1");
|
||||||
|
const tab2: any = component.queryByText("Tab 2");
|
||||||
|
expect(tab1).toBeDefined();
|
||||||
|
expect(tab2).toBeDefined();
|
||||||
|
let tab1Switch = component.queryByText("Tab1 Switch");
|
||||||
|
let tab1Checkbox = component.queryByText("Tab1 Checkbox");
|
||||||
|
let tab2Input = component.queryByText("Tab2 Text");
|
||||||
|
let tab2Button = component.queryByText("Tab2 Button");
|
||||||
|
expect(tab1Switch).toBeDefined();
|
||||||
|
expect(tab1Checkbox).toBeDefined();
|
||||||
|
expect(tab2Input).toBeNull();
|
||||||
|
expect(tab2Button).toBeNull();
|
||||||
|
fireEvent.click(tab2);
|
||||||
|
tab1Switch = component.queryByText("Tab1 Switch");
|
||||||
|
tab1Checkbox = component.queryByText("Tab1 Checkbox");
|
||||||
|
tab2Input = component.queryByText("Tab2 Text");
|
||||||
|
tab2Button = component.queryByText("Tab2 Button");
|
||||||
|
expect(tab1Switch).toBeNull();
|
||||||
|
expect(tab1Checkbox).toBeNull();
|
||||||
|
expect(tab2Input).toBeDefined();
|
||||||
|
expect(tab2Button).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import TabsComponent from "components/designSystems/appsmith/TabsComponent";
|
import TabsComponent from "components/designSystems/appsmith/TabsComponent";
|
||||||
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
|
import { WidgetType, WidgetTypes } from "constants/WidgetConstants";
|
||||||
import BaseWidget, { WidgetProps, WidgetState } from "./BaseWidget";
|
import BaseWidget, { WidgetProps, WidgetState } from "../BaseWidget";
|
||||||
import WidgetFactory from "utils/WidgetFactory";
|
import WidgetFactory from "utils/WidgetFactory";
|
||||||
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
import { VALIDATION_TYPES } from "constants/WidgetValidation";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
|
@ -9,7 +9,7 @@ import { EventType } from "constants/AppsmithActionConstants/ActionConstants";
|
||||||
import { WidgetOperations } from "widgets/BaseWidget";
|
import { WidgetOperations } from "widgets/BaseWidget";
|
||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
import { generateReactKey } from "utils/generators";
|
import { generateReactKey } from "utils/generators";
|
||||||
import withMeta, { WithMeta } from "./MetaHOC";
|
import withMeta, { WithMeta } from "../MetaHOC";
|
||||||
|
|
||||||
class TabsWidget extends BaseWidget<
|
class TabsWidget extends BaseWidget<
|
||||||
TabsWidgetProps<TabContainerWidgetProps>,
|
TabsWidgetProps<TabContainerWidgetProps>,
|
||||||
|
|
@ -22,13 +22,47 @@ class TabsWidget extends BaseWidget<
|
||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
helpText: "Takes an array of tab names to render tabs",
|
helpText: "Takes an array of tab names to render tabs",
|
||||||
propertyName: "tabs",
|
propertyName: "tabsObj",
|
||||||
isJSConvertible: true,
|
isJSConvertible: false,
|
||||||
label: "Tabs",
|
label: "Tabs",
|
||||||
controlType: "TABS_INPUT",
|
controlType: "TABS_INPUT",
|
||||||
|
isBindProperty: false,
|
||||||
|
isTriggerProperty: false,
|
||||||
|
panelConfig: {
|
||||||
|
editableTitle: true,
|
||||||
|
titlePropertyName: "label",
|
||||||
|
panelIdPropertyName: "id",
|
||||||
|
updateHook: (
|
||||||
|
props: any,
|
||||||
|
propertyPath: string,
|
||||||
|
propertyValue: string,
|
||||||
|
) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
propertyPath,
|
||||||
|
propertyValue,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
},
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
sectionName: "Tab Control",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
propertyName: "isVisible",
|
||||||
|
label: "Visible",
|
||||||
|
helpText: "Controls the visibility of the widget",
|
||||||
|
controlType: "SWITCH",
|
||||||
|
useValidationMessage: true,
|
||||||
|
isJSConvertible: true,
|
||||||
isBindProperty: true,
|
isBindProperty: true,
|
||||||
isTriggerProperty: false,
|
isTriggerProperty: false,
|
||||||
validation: VALIDATION_TYPES.TABS_DATA,
|
validation: VALIDATION_TYPES.BOOLEAN,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
propertyName: "defaultTab",
|
propertyName: "defaultTab",
|
||||||
|
|
@ -97,7 +131,9 @@ class TabsWidget extends BaseWidget<
|
||||||
|
|
||||||
static getDerivedPropertiesMap() {
|
static getDerivedPropertiesMap() {
|
||||||
return {
|
return {
|
||||||
selectedTab: `{{_.find(this.tabs, { widgetId: this.selectedTabWidgetId }).label}}`,
|
selectedTab: `{{_.find(Object.values(this.tabsObj), {
|
||||||
|
widgetId: this.selectedTabWidgetId,
|
||||||
|
}).label}}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,8 +188,11 @@ class TabsWidget extends BaseWidget<
|
||||||
}
|
}
|
||||||
|
|
||||||
addTabContainer = (widgetIds: string[]) => {
|
addTabContainer = (widgetIds: string[]) => {
|
||||||
|
const tabs = Object.values(this.props.tabsObj || {});
|
||||||
widgetIds.forEach((newWidgetId: string) => {
|
widgetIds.forEach((newWidgetId: string) => {
|
||||||
const tab = this.props.tabs.find((tab) => tab.widgetId === newWidgetId);
|
const tab = _.find(tabs, {
|
||||||
|
widgetId: newWidgetId,
|
||||||
|
});
|
||||||
if (tab) {
|
if (tab) {
|
||||||
const columns =
|
const columns =
|
||||||
(this.props.rightColumn - this.props.leftColumn) *
|
(this.props.rightColumn - this.props.leftColumn) *
|
||||||
|
|
@ -186,6 +225,18 @@ class TabsWidget extends BaseWidget<
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
updateTabContainerNames = () => {
|
||||||
|
this.props.children.forEach((each) => {
|
||||||
|
const tab = this.props.tabsObj[each.tabId];
|
||||||
|
if (tab && each.tabName !== tab.label) {
|
||||||
|
this.updateWidget(WidgetOperations.UPDATE_PROPERTY, each.widgetId, {
|
||||||
|
propertyPath: "tabName",
|
||||||
|
propertyValue: tab.label,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
removeTabContainer = (widgetIds: string[]) => {
|
removeTabContainer = (widgetIds: string[]) => {
|
||||||
widgetIds.forEach((widgetIdToRemove: string) => {
|
widgetIds.forEach((widgetIdToRemove: string) => {
|
||||||
this.updateWidget(WidgetOperations.DELETE, widgetIdToRemove, {
|
this.updateWidget(WidgetOperations.DELETE, widgetIdToRemove, {
|
||||||
|
|
@ -196,17 +247,17 @@ class TabsWidget extends BaseWidget<
|
||||||
|
|
||||||
componentDidUpdate(prevProps: TabsWidgetProps<TabContainerWidgetProps>) {
|
componentDidUpdate(prevProps: TabsWidgetProps<TabContainerWidgetProps>) {
|
||||||
if (
|
if (
|
||||||
Array.isArray(this.props.tabs) &&
|
JSON.stringify(this.props.tabsObj) !== JSON.stringify(prevProps.tabsObj)
|
||||||
JSON.stringify(this.props.tabs) !== JSON.stringify(prevProps.tabs)
|
|
||||||
) {
|
) {
|
||||||
const tabWidgetIds = this.props.tabs.map((tab) => tab.widgetId);
|
const tabWidgetIds = Object.values(this.props.tabsObj).map(
|
||||||
|
(tab) => tab.widgetId,
|
||||||
|
);
|
||||||
const childWidgetIds = this.props.children
|
const childWidgetIds = this.props.children
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.map((child) => child.widgetId);
|
.map((child) => child.widgetId);
|
||||||
// If the tabs and children are different,
|
// If the tabs and children are different,
|
||||||
// add and/or remove tab container widgets
|
// add and/or remove tab container widgets
|
||||||
|
|
||||||
if (!this.props.invalidProps?.tabs) {
|
|
||||||
if (_.xor(childWidgetIds, tabWidgetIds).length > 0) {
|
if (_.xor(childWidgetIds, tabWidgetIds).length > 0) {
|
||||||
const widgetIdsToRemove: string[] = _.without(
|
const widgetIdsToRemove: string[] = _.without(
|
||||||
childWidgetIds,
|
childWidgetIds,
|
||||||
|
|
@ -216,18 +267,27 @@ class TabsWidget extends BaseWidget<
|
||||||
tabWidgetIds,
|
tabWidgetIds,
|
||||||
...childWidgetIds,
|
...childWidgetIds,
|
||||||
);
|
);
|
||||||
|
if (widgetIdsToCreate && widgetIdsToCreate.length) {
|
||||||
this.addTabContainer(widgetIdsToCreate);
|
this.addTabContainer(widgetIdsToCreate);
|
||||||
|
}
|
||||||
|
if (widgetIdsToRemove && widgetIdsToRemove.length) {
|
||||||
this.removeTabContainer(widgetIdsToRemove);
|
this.removeTabContainer(widgetIdsToRemove);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
this.updateTabContainerNames();
|
||||||
|
|
||||||
// If all tabs were removed.
|
// If all tabs were removed.
|
||||||
if (tabWidgetIds.length === 0) {
|
if (tabWidgetIds.length === 0) {
|
||||||
const newTabContainerWidgetId = generateReactKey();
|
const newTabContainerWidgetId = generateReactKey();
|
||||||
const tabs = [
|
const tabs = {
|
||||||
{ id: "tab1", widgetId: newTabContainerWidgetId, label: "Tab 1" },
|
tab1: {
|
||||||
];
|
id: "tab1",
|
||||||
this.updateWidgetProperty("tabs", tabs);
|
widgetId: newTabContainerWidgetId,
|
||||||
}
|
label: "Tab 1",
|
||||||
|
index: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this.updateWidgetProperty("tabsObj", tabs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const visibleTabs = this.getVisibleTabs();
|
const visibleTabs = this.getVisibleTabs();
|
||||||
|
|
@ -276,7 +336,8 @@ class TabsWidget extends BaseWidget<
|
||||||
}
|
}
|
||||||
|
|
||||||
generateTabContainers = () => {
|
generateTabContainers = () => {
|
||||||
const { tabs, widgetId } = this.props;
|
const { tabsObj, widgetId } = this.props;
|
||||||
|
const tabs = Object.values(tabsObj || {});
|
||||||
const childWidgetIds = this.props.children
|
const childWidgetIds = this.props.children
|
||||||
?.filter(Boolean)
|
?.filter(Boolean)
|
||||||
.map((child) => child.widgetId);
|
.map((child) => child.widgetId);
|
||||||
|
|
@ -312,10 +373,13 @@ class TabsWidget extends BaseWidget<
|
||||||
};
|
};
|
||||||
|
|
||||||
getVisibleTabs = () => {
|
getVisibleTabs = () => {
|
||||||
if (Array.isArray(this.props.tabs)) {
|
const tabs = Object.values(this.props.tabsObj || {});
|
||||||
return this.props.tabs.filter(
|
if (tabs.length) {
|
||||||
(tab) => tab.isVisible === undefined || tab.isVisible === true,
|
return tabs
|
||||||
);
|
.filter(
|
||||||
|
(tab) => tab.isVisible === undefined || !!tab.isVisible === true,
|
||||||
|
)
|
||||||
|
.sort((tab1, tab2) => tab1.index - tab2.index);
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
|
|
@ -323,7 +387,7 @@ class TabsWidget extends BaseWidget<
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const visibleTabs = this.getVisibleTabs();
|
const visibleTabs = this.getVisibleTabs();
|
||||||
// If we have a defaultTab
|
// If we have a defaultTab
|
||||||
if (this.props.defaultTab && this.props.tabs?.length) {
|
if (this.props.defaultTab && Object.keys(this.props.tabsObj || {}).length) {
|
||||||
// Find the default Tab object
|
// Find the default Tab object
|
||||||
const selectedTab = _.find(visibleTabs, {
|
const selectedTab = _.find(visibleTabs, {
|
||||||
label: this.props.defaultTab,
|
label: this.props.defaultTab,
|
||||||
|
|
@ -345,7 +409,10 @@ class TabsWidget extends BaseWidget<
|
||||||
selectedTabWidgetId,
|
selectedTabWidgetId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (!this.props.selectedTabWidgetId && this.props.tabs?.length) {
|
} else if (
|
||||||
|
!this.props.selectedTabWidgetId &&
|
||||||
|
Object.keys(this.props.tabsObj || {}).length
|
||||||
|
) {
|
||||||
// If no tab is selected
|
// If no tab is selected
|
||||||
// Select the first tab in the tabs list.
|
// Select the first tab in the tabs list.
|
||||||
this.props.updateWidgetMetaProperty(
|
this.props.updateWidgetMetaProperty(
|
||||||
|
|
@ -372,6 +439,16 @@ export interface TabsWidgetProps<T extends TabContainerWidgetProps>
|
||||||
widgetId: string;
|
widgetId: string;
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
}>;
|
}>;
|
||||||
|
tabsObj: Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
widgetId: string;
|
||||||
|
isVisible?: boolean;
|
||||||
|
index: number;
|
||||||
|
}
|
||||||
|
>;
|
||||||
shouldShowTabs: boolean;
|
shouldShowTabs: boolean;
|
||||||
children: T[];
|
children: T[];
|
||||||
snapColumns?: number;
|
snapColumns?: number;
|
||||||
|
|
@ -741,18 +741,15 @@ export const VALIDATORS: Record<VALIDATION_TYPES, Validator> = {
|
||||||
value: any,
|
value: any,
|
||||||
props: WidgetProps,
|
props: WidgetProps,
|
||||||
): ValidationResponse => {
|
): ValidationResponse => {
|
||||||
const tabs =
|
const tabs: any = props.tabsObj
|
||||||
props.tabs && isString(props.tabs)
|
? Object.values(props.tabsObj)
|
||||||
? JSON.parse(props.tabs)
|
: props.tabs || [];
|
||||||
: props.tabs && Array.isArray(props.tabs)
|
|
||||||
? props.tabs
|
|
||||||
: [];
|
|
||||||
const tabNames = tabs.map((i: { label: string; id: string }) => i.label);
|
const tabNames = tabs.map((i: { label: string; id: string }) => i.label);
|
||||||
const isValidTabName = tabNames.includes(value);
|
const isValidTabName = tabNames.includes(value);
|
||||||
return {
|
return {
|
||||||
isValid: isValidTabName,
|
isValid: isValidTabName,
|
||||||
parsed: value,
|
parsed: isValidTabName ? value : "",
|
||||||
message: isValidTabName ? "" : `Invalid tab name.`,
|
message: isValidTabName ? "" : `Tab name provided does not exist.`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
[VALIDATION_TYPES.DEFAULT_OPTION_VALUE]: (
|
[VALIDATION_TYPES.DEFAULT_OPTION_VALUE]: (
|
||||||
|
|
|
||||||
3
app/client/test/__mocks__/derivedMock.js
Normal file
3
app/client/test/__mocks__/derivedMock.js
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
import widgetPropertyFns from "!!raw-loader!./derived.js";
|
||||||
|
|
||||||
|
export default widgetPropertyFns;
|
||||||
28
app/client/test/factories/WidgetFactoryUtils.ts
Normal file
28
app/client/test/factories/WidgetFactoryUtils.ts
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { makeFactory } from "factory.ts";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
import { ContainerWidgetProps } from "widgets/ContainerWidget";
|
||||||
|
import defaultTemplate from "../../src/templates/default";
|
||||||
|
import { WidgetTypeFactories } from "./Widgets/WidgetTypeFactories";
|
||||||
|
const defaultMainContainer: ContainerWidgetProps<WidgetProps> = {
|
||||||
|
...(defaultTemplate as any),
|
||||||
|
renderMode: "PAGE",
|
||||||
|
version: 1,
|
||||||
|
isLoading: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mainContainerFactory = makeFactory({ ...defaultMainContainer });
|
||||||
|
export const widgetCanvasFactory = makeFactory(mainContainerFactory.build());
|
||||||
|
const buildChild = (child: Partial<WidgetProps>): WidgetProps => {
|
||||||
|
return WidgetTypeFactories[child.type || "CANVAS_WIDGET"].build({
|
||||||
|
...child,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export const buildChildren = (children: Partial<WidgetProps>[]) => {
|
||||||
|
try {
|
||||||
|
return children.map((child) => {
|
||||||
|
return buildChild(child);
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Check if child widget data provided");
|
||||||
|
}
|
||||||
|
};
|
||||||
31
app/client/test/factories/Widgets/ButtonFactory.ts
Normal file
31
app/client/test/factories/Widgets/ButtonFactory.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const ButtonFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
widgetName: Factory.each((i) => `Button${i + 1}`),
|
||||||
|
rightColumn: 12,
|
||||||
|
onClick: "",
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
topRow: 1,
|
||||||
|
bottomRow: 2,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
parentId: "0",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
leftColumn: 10,
|
||||||
|
dynamicTriggerPathList: [
|
||||||
|
{
|
||||||
|
key: "onClick",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
text: "Test Button Text",
|
||||||
|
isDisabled: false,
|
||||||
|
version: 1,
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
});
|
||||||
25
app/client/test/factories/Widgets/CanvasFactory.ts
Normal file
25
app/client/test/factories/Widgets/CanvasFactory.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const CanvasFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
backgroundColor: "none",
|
||||||
|
rightColumn: 1224,
|
||||||
|
snapColumns: 16,
|
||||||
|
detachFromLayout: true,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 1280,
|
||||||
|
containerStyle: "none",
|
||||||
|
snapRows: 33,
|
||||||
|
parentRowSpace: 1,
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
canExtend: true,
|
||||||
|
minHeight: 1292,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
leftColumn: 0,
|
||||||
|
widgetName: Factory.each((i) => `Canvas${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
61
app/client/test/factories/Widgets/ChartFactory.ts
Normal file
61
app/client/test/factories/Widgets/ChartFactory.ts
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const ChartFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
chartType: "LINE_CHART",
|
||||||
|
chartName: "Sales on working days",
|
||||||
|
allowHorizontalScroll: false,
|
||||||
|
chartData: [
|
||||||
|
{
|
||||||
|
seriesName: "Sales",
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
x: "Mon",
|
||||||
|
y: 10000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: "Tue",
|
||||||
|
y: 12000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: "Wed",
|
||||||
|
y: 32000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: "Thu",
|
||||||
|
y: 28000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: "Fri",
|
||||||
|
y: 14000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: "Sat",
|
||||||
|
y: 19000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: "Sun",
|
||||||
|
y: 36000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
xAxisName: "Last Week",
|
||||||
|
yAxisName: "Total Order Revenue $",
|
||||||
|
type: "CHART_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 71.75,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
leftColumn: 2,
|
||||||
|
rightColumn: 8,
|
||||||
|
topRow: 1,
|
||||||
|
bottomRow: 9,
|
||||||
|
parentId: "rglduihhzk",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Chart${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
23
app/client/test/factories/Widgets/CheckboxFactory.ts
Normal file
23
app/client/test/factories/Widgets/CheckboxFactory.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const CheckboxFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
label: "Label",
|
||||||
|
defaultCheckedState: true,
|
||||||
|
type: "CHECKBOX_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 71.75,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
leftColumn: 10,
|
||||||
|
rightColumn: 13,
|
||||||
|
topRow: 4,
|
||||||
|
bottomRow: 5,
|
||||||
|
parentId: "e3tq9qwta6",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Checkbox${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
25
app/client/test/factories/Widgets/ContainerFactory.ts
Normal file
25
app/client/test/factories/Widgets/ContainerFactory.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const ContainerFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
backgroundColor: "#FFFFFF",
|
||||||
|
widgetName: Factory.each((i) => `Container${(i+1)}` ),
|
||||||
|
type: "CONTAINER_WIDGET",
|
||||||
|
containerStyle: "card",
|
||||||
|
isVisible: true,
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 75.25,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
leftColumn: 0,
|
||||||
|
rightColumn: 8,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 9,
|
||||||
|
snapColumns: 16,
|
||||||
|
orientation: "VERTICAL",
|
||||||
|
children: [],
|
||||||
|
version: 1,
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
});
|
||||||
47
app/client/test/factories/Widgets/DatepickerFactory.ts
Normal file
47
app/client/test/factories/Widgets/DatepickerFactory.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const OldDatepickerFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
widgetName: Factory.each((i) => `OldDatePicker${i + 1}`),
|
||||||
|
rightColumn: 11,
|
||||||
|
dateFormat: "DD/MM/YYYY",
|
||||||
|
topRow: 7,
|
||||||
|
bottomRow: 8,
|
||||||
|
isValid: "{{ DatePicker1.isRequired ? !!DatePicker1.selectedDate : true }}",
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
datePickerType: "DATE_PICKER",
|
||||||
|
label: "From Date",
|
||||||
|
type: "DATE_PICKER_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
isLoading: false,
|
||||||
|
enableTimePicker: true,
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
leftColumn: 3,
|
||||||
|
isDisabled: false,
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const DatepickerFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
widgetName: Factory.each((i) => `DatePicker${i + 1}`),
|
||||||
|
isVisible: true,
|
||||||
|
isDisabled: false,
|
||||||
|
datePickerType: "DATE_PICKER",
|
||||||
|
label: "",
|
||||||
|
dateFormat: "DD/MM/YYYY HH:mm",
|
||||||
|
defaultDate: "2021-02-05T10:53:12.791Z",
|
||||||
|
version: 2,
|
||||||
|
type: "DATE_PICKER_WIDGET2",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 74,
|
||||||
|
parentRowSpace: 40,
|
||||||
|
leftColumn: 5,
|
||||||
|
rightColumn: 10,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 1,
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
parentId: "0",
|
||||||
|
});
|
||||||
29
app/client/test/factories/Widgets/DropdownFactory.ts
Normal file
29
app/client/test/factories/Widgets/DropdownFactory.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const DropdownFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
label: "",
|
||||||
|
selectionType: "SINGLE_SELECT",
|
||||||
|
options: [
|
||||||
|
{ label: "Vegetarian", value: "VEG" },
|
||||||
|
{ label: "Non-Vegetarian", value: "NON_VEG" },
|
||||||
|
{ label: "Vegan", value: "VEGAN" },
|
||||||
|
],
|
||||||
|
defaultOptionValue: "VEG",
|
||||||
|
type: "DROP_DOWN_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 74,
|
||||||
|
parentRowSpace: 40,
|
||||||
|
leftColumn: 10,
|
||||||
|
rightColumn: 15,
|
||||||
|
topRow: 1,
|
||||||
|
bottomRow: 2,
|
||||||
|
parentId: "0",
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Dropdown${i + 1}`),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
25
app/client/test/factories/Widgets/FilepickerFactory.ts
Normal file
25
app/client/test/factories/Widgets/FilepickerFactory.ts
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const FilepickerFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
rightColumn: 8,
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
topRow: 1,
|
||||||
|
bottomRow: 2,
|
||||||
|
isValid: "{{ FilePicker1.isRequired ? FilePicker1.files.length > 0 : true }}",
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
label: "Upload Files",
|
||||||
|
maxFileSize: "",
|
||||||
|
type: "FILE_PICKER_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
leftColumn: 4,
|
||||||
|
files: [],
|
||||||
|
widgetName: Factory.each((i) => `FilePicker${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
24
app/client/test/factories/Widgets/FormButtonFactory.ts
Normal file
24
app/client/test/factories/Widgets/FormButtonFactory.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const FormButtonFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
text: "Reset",
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
buttonStyle: "SECONDARY_BUTTON",
|
||||||
|
disabledWhenInvalid: false,
|
||||||
|
resetFormOnClick: true,
|
||||||
|
type: "FORM_BUTTON_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
leftColumn: 8,
|
||||||
|
rightColumn: 12,
|
||||||
|
topRow: 12,
|
||||||
|
bottomRow: 13,
|
||||||
|
parentId: "qrqizehc5b",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `FormButton${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
217
app/client/test/factories/Widgets/FormFactory.ts
Normal file
217
app/client/test/factories/Widgets/FormFactory.ts
Normal file
|
|
@ -0,0 +1,217 @@
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const FormFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
backgroundColor: "Gray",
|
||||||
|
rightColumn: 11,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 13,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
type: "FORM_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
blueprint: {
|
||||||
|
view: [
|
||||||
|
{
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
props: {
|
||||||
|
blueprint: {
|
||||||
|
view: [
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 12,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
type: "TEXT_WIDGET",
|
||||||
|
props: {
|
||||||
|
text: "Title",
|
||||||
|
textStyle: "HEADING",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 4,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 11,
|
||||||
|
left: 12,
|
||||||
|
},
|
||||||
|
type: "FORM_BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
resetFormOnClick: false,
|
||||||
|
disabledWhenInvalid: true,
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
text: "Submit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 4,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 11,
|
||||||
|
left: 8,
|
||||||
|
},
|
||||||
|
type: "FORM_BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
resetFormOnClick: true,
|
||||||
|
disabledWhenInvalid: false,
|
||||||
|
buttonStyle: "SECONDARY_BUTTON",
|
||||||
|
text: "Reset",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
detachFromLayout: true,
|
||||||
|
children: [],
|
||||||
|
containerStyle: "none",
|
||||||
|
canExtend: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 71.75,
|
||||||
|
leftColumn: 5,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
widgetName: "Canvas1",
|
||||||
|
rightColumn: 430.5,
|
||||||
|
detachFromLayout: true,
|
||||||
|
widgetId: "nxlutw2g3v",
|
||||||
|
containerStyle: "none",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 494,
|
||||||
|
parentRowSpace: 1,
|
||||||
|
isVisible: true,
|
||||||
|
canExtend: false,
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
blueprint: {
|
||||||
|
view: [
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 12,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
type: "TEXT_WIDGET",
|
||||||
|
props: {
|
||||||
|
text: "Title",
|
||||||
|
textStyle: "HEADING",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 4,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 11,
|
||||||
|
left: 12,
|
||||||
|
},
|
||||||
|
type: "FORM_BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
resetFormOnClick: false,
|
||||||
|
disabledWhenInvalid: true,
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
text: "Submit",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 4,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 11,
|
||||||
|
left: 8,
|
||||||
|
},
|
||||||
|
type: "FORM_BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
resetFormOnClick: true,
|
||||||
|
disabledWhenInvalid: false,
|
||||||
|
buttonStyle: "SECONDARY_BUTTON",
|
||||||
|
text: "Reset",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
minHeight: 494,
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
leftColumn: 0,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
isLoading: false,
|
||||||
|
widgetName: "Text1",
|
||||||
|
rightColumn: 12,
|
||||||
|
leftColumn: 0,
|
||||||
|
widgetId: "uvz6hzdz7c",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 1,
|
||||||
|
isVisible: true,
|
||||||
|
text: "Title",
|
||||||
|
textStyle: "HEADING",
|
||||||
|
type: "TEXT_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resetFormOnClick: false,
|
||||||
|
widgetName: "FormButton1",
|
||||||
|
rightColumn: 16,
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
widgetId: "tf20n9k4z2",
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
topRow: 11,
|
||||||
|
bottomRow: 12,
|
||||||
|
isVisible: true,
|
||||||
|
type: "FORM_BUTTON_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
isLoading: false,
|
||||||
|
disabledWhenInvalid: true,
|
||||||
|
leftColumn: 12,
|
||||||
|
text: "Submit",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
resetFormOnClick: true,
|
||||||
|
widgetName: "FormButton2",
|
||||||
|
rightColumn: 12,
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
widgetId: "6xnpe13jie",
|
||||||
|
buttonStyle: "SECONDARY_BUTTON",
|
||||||
|
topRow: 11,
|
||||||
|
bottomRow: 12,
|
||||||
|
isVisible: true,
|
||||||
|
type: "FORM_BUTTON_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
isLoading: false,
|
||||||
|
disabledWhenInvalid: false,
|
||||||
|
leftColumn: 8,
|
||||||
|
text: "Reset",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
widgetName: Factory.each((i) => `Form${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
23
app/client/test/factories/Widgets/IconFactory.ts
Normal file
23
app/client/test/factories/Widgets/IconFactory.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const IconFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
rightColumn: 16,
|
||||||
|
onClick: "",
|
||||||
|
color: "#040627",
|
||||||
|
iconName: "cross",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 1,
|
||||||
|
isVisible: true,
|
||||||
|
type: "ICON_WIDGET",
|
||||||
|
parentId: "dma7flgdrm",
|
||||||
|
isLoading: false,
|
||||||
|
leftColumn: 15,
|
||||||
|
iconSize: 24,
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Icon${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
24
app/client/test/factories/Widgets/ImageFactory.ts
Normal file
24
app/client/test/factories/Widgets/ImageFactory.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const ImageFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
defaultImage:
|
||||||
|
"https://res.cloudinary.com/drako999/image/upload/v1589196259/default.png",
|
||||||
|
imageShape: "RECTANGLE",
|
||||||
|
image: "",
|
||||||
|
widgetName: Factory.each((i) => `Image${i + 1}`),
|
||||||
|
type: "IMAGE_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
leftColumn: 6,
|
||||||
|
rightColumn: 10,
|
||||||
|
topRow: 2,
|
||||||
|
bottomRow: 5,
|
||||||
|
parentId: "bxekwxgc1i",
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
30
app/client/test/factories/Widgets/InputFactory.ts
Normal file
30
app/client/test/factories/Widgets/InputFactory.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const InputFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
widgetName: Factory.each((i) => `Input${i + 1}`),
|
||||||
|
onTextChanged: "",
|
||||||
|
rightColumn: 11,
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
topRow: 6,
|
||||||
|
bottomRow: 7,
|
||||||
|
isValid: "",
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
label: "Test Input Label",
|
||||||
|
type: "INPUT_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
parentId: "iw4o07jvik",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
leftColumn: 6,
|
||||||
|
dynamicTriggerPathList: [
|
||||||
|
{
|
||||||
|
key: "onTextChange",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
inputType: "",
|
||||||
|
placeholderText: "",
|
||||||
|
defaultText: "",
|
||||||
|
});
|
||||||
23
app/client/test/factories/Widgets/ListFactory.ts
Normal file
23
app/client/test/factories/Widgets/ListFactory.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const ListFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
image: "",
|
||||||
|
defaultImage: "",
|
||||||
|
type: "LIST_WIDGET",
|
||||||
|
parentId: "Container1",
|
||||||
|
parentColumnSpace: 2,
|
||||||
|
parentRowSpace: 3,
|
||||||
|
leftColumn: 2,
|
||||||
|
rightColumn: 3,
|
||||||
|
topRow: 1,
|
||||||
|
bottomRow: 3,
|
||||||
|
isLoading: false,
|
||||||
|
items: [],
|
||||||
|
disablePropertyPane: false,
|
||||||
|
widgetName: Factory.each((i) => `List${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
32
app/client/test/factories/Widgets/MapFactory.ts
Normal file
32
app/client/test/factories/Widgets/MapFactory.ts
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const MapFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
isDisabled: false,
|
||||||
|
enableSearch: true,
|
||||||
|
zoomLevel: 50,
|
||||||
|
enablePickLocation: true,
|
||||||
|
allowZoom: true,
|
||||||
|
mapCenter: {
|
||||||
|
lat: 20.593684,
|
||||||
|
long: 78.96288,
|
||||||
|
},
|
||||||
|
defaultMarkers:
|
||||||
|
'[\n {\n "lat: -34.397,\n "long: 150.644,\n "title: "Test A"\n }\n]',
|
||||||
|
type: "MAP_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 71.75,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
leftColumn: 3,
|
||||||
|
rightColumn: 11,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 12,
|
||||||
|
parentId: "yt4ouwn0sk",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Map${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
270
app/client/test/factories/Widgets/ModalFactory.ts
Normal file
270
app/client/test/factories/Widgets/ModalFactory.ts
Normal file
|
|
@ -0,0 +1,270 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const ModalFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
rightColumn: 0,
|
||||||
|
detachFromLayout: true,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 0,
|
||||||
|
parentRowSpace: 1,
|
||||||
|
isVisible: false,
|
||||||
|
canOutsideClickClose: true,
|
||||||
|
type: "MODAL_WIDGET",
|
||||||
|
canEscapeKeyClose: true,
|
||||||
|
parentId: "0",
|
||||||
|
shouldScrollContents: true,
|
||||||
|
blueprint: {
|
||||||
|
view: [
|
||||||
|
{
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
props: {
|
||||||
|
shouldScrollContents: false,
|
||||||
|
blueprint: {
|
||||||
|
view: [
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 1,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 15,
|
||||||
|
},
|
||||||
|
type: "ICON_WIDGET",
|
||||||
|
props: {
|
||||||
|
color: "#040627",
|
||||||
|
iconName: "cross",
|
||||||
|
iconSize: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 15,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
type: "TEXT_WIDGET",
|
||||||
|
props: {
|
||||||
|
text: "Modal Title",
|
||||||
|
textStyle: "HEADING",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 3,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 4,
|
||||||
|
left: 10,
|
||||||
|
},
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
buttonStyle: "SECONDARY_BUTTON",
|
||||||
|
text: "Cancel",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 3,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 4,
|
||||||
|
left: 13,
|
||||||
|
},
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
text: "Confirm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
type: "MODIFY_PROPS",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
detachFromLayout: true,
|
||||||
|
children: [],
|
||||||
|
isVisible: true,
|
||||||
|
isDisabled: false,
|
||||||
|
canExtend: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
size: "MODAL_SMALL",
|
||||||
|
leftColumn: 0,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
widgetName: "Canvas1",
|
||||||
|
rightColumn: 0,
|
||||||
|
detachFromLayout: true,
|
||||||
|
widgetId: "dma7flgdrm",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 0,
|
||||||
|
parentRowSpace: 1,
|
||||||
|
isVisible: true,
|
||||||
|
canExtend: true,
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
parentId: "s8mtp5krfz",
|
||||||
|
shouldScrollContents: false,
|
||||||
|
blueprint: {
|
||||||
|
view: [
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 1,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 15,
|
||||||
|
},
|
||||||
|
type: "ICON_WIDGET",
|
||||||
|
props: {
|
||||||
|
color: "#040627",
|
||||||
|
iconName: "cross",
|
||||||
|
iconSize: 24,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 15,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 0,
|
||||||
|
left: 0,
|
||||||
|
},
|
||||||
|
type: "TEXT_WIDGET",
|
||||||
|
props: {
|
||||||
|
text: "Modal Title",
|
||||||
|
textStyle: "HEADING",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 3,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 4,
|
||||||
|
left: 10,
|
||||||
|
},
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
buttonStyle: "SECONDARY_BUTTON",
|
||||||
|
text: "Cancel",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
size: {
|
||||||
|
rows: 1,
|
||||||
|
cols: 3,
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
top: 4,
|
||||||
|
left: 13,
|
||||||
|
},
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
props: {
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
text: "Confirm",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
operations: [
|
||||||
|
{
|
||||||
|
type: "MODIFY_PROPS",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
minHeight: 0,
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
leftColumn: 0,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
widgetName: "Icon1",
|
||||||
|
rightColumn: 16,
|
||||||
|
onClick: "{{closeModal('TestModal')}}",
|
||||||
|
color: "#040627",
|
||||||
|
iconName: "cross",
|
||||||
|
widgetId: "n5fc0ven2a",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 1,
|
||||||
|
isVisible: true,
|
||||||
|
type: "ICON_WIDGET",
|
||||||
|
parentId: "dma7flgdrm",
|
||||||
|
isLoading: false,
|
||||||
|
leftColumn: 15,
|
||||||
|
iconSize: 24,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isLoading: false,
|
||||||
|
widgetName: "Text1",
|
||||||
|
rightColumn: 15,
|
||||||
|
leftColumn: 0,
|
||||||
|
widgetId: "s818l5hhvq",
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 1,
|
||||||
|
isVisible: true,
|
||||||
|
text: "Modal Title",
|
||||||
|
textStyle: "HEADING",
|
||||||
|
type: "TEXT_WIDGET",
|
||||||
|
parentId: "dma7flgdrm",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
widgetName: "Button1",
|
||||||
|
rightColumn: 13,
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
widgetId: "io777lh7bc",
|
||||||
|
buttonStyle: "SECONDARY_BUTTON",
|
||||||
|
topRow: 4,
|
||||||
|
bottomRow: 5,
|
||||||
|
isVisible: true,
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
parentId: "dma7flgdrm",
|
||||||
|
isLoading: false,
|
||||||
|
leftColumn: 10,
|
||||||
|
text: "Cancel",
|
||||||
|
isDisabled: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
widgetName: "Button2",
|
||||||
|
rightColumn: 16,
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
widgetId: "gexp49bfyb",
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
topRow: 4,
|
||||||
|
bottomRow: 5,
|
||||||
|
isVisible: true,
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
parentId: "dma7flgdrm",
|
||||||
|
isLoading: false,
|
||||||
|
leftColumn: 13,
|
||||||
|
text: "Confirm",
|
||||||
|
isDisabled: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
isDisabled: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Modal${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
42
app/client/test/factories/Widgets/RadiogroupFactory.ts
Normal file
42
app/client/test/factories/Widgets/RadiogroupFactory.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const RadiogroupFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
rightColumn: 16,
|
||||||
|
topRow: 3,
|
||||||
|
bottomRow: 5,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
label: "Test Radio",
|
||||||
|
type: "RADIO_GROUP_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
defaultOptionValue: "1",
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
leftColumn: 12,
|
||||||
|
dynamicTriggerPathList: [{
|
||||||
|
key: "onSelectionChange"
|
||||||
|
}],
|
||||||
|
onSelectionChange: "{{navigateTo()}}",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "1",
|
||||||
|
label: "jarvis",
|
||||||
|
value: "1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "2",
|
||||||
|
label: "marvel",
|
||||||
|
value: "2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "iron",
|
||||||
|
value: "4"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `RadioGroup${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
29
app/client/test/factories/Widgets/RichTextFactory.ts
Normal file
29
app/client/test/factories/Widgets/RichTextFactory.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const RichTextFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
rightColumn: 11,
|
||||||
|
topRow: 3,
|
||||||
|
bottomRow: 8,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
type: "RICH_TEXT_EDITOR_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
leftColumn: 3,
|
||||||
|
dynamicTriggerPathList: [
|
||||||
|
{
|
||||||
|
key: "onTextChange",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
defaultText: "",
|
||||||
|
text: "This is the initial <b>content</b> of the editor",
|
||||||
|
isDisabled: false,
|
||||||
|
onTextChange: "{{navigateTo()}}",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `RichText${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
19
app/client/test/factories/Widgets/SkeletonFactory.ts
Normal file
19
app/client/test/factories/Widgets/SkeletonFactory.ts
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const SkeletonFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
bottomRow: 0,
|
||||||
|
isLoading: false,
|
||||||
|
leftColumn: 0,
|
||||||
|
parentColumnSpace: 0,
|
||||||
|
parentRowSpace: 0,
|
||||||
|
rightColumn: 0,
|
||||||
|
topRow: 0,
|
||||||
|
type: "SKELETON_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Skeleton${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
22
app/client/test/factories/Widgets/SwitchFactory.ts
Normal file
22
app/client/test/factories/Widgets/SwitchFactory.ts
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const SwitchFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
label: "Switch",
|
||||||
|
defaultSwitchState: true,
|
||||||
|
widgetName: Factory.each((i) => `Switch${(i+1)}` ),
|
||||||
|
type: "SWITCH_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 71.75,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
leftColumn: 10,
|
||||||
|
rightColumn: 13,
|
||||||
|
topRow: 18,
|
||||||
|
bottomRow: 19,
|
||||||
|
parentId: "e3tq9qwta6",
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
111
app/client/test/factories/Widgets/TableFactory.ts
Normal file
111
app/client/test/factories/Widgets/TableFactory.ts
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const TableFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
label: "Data",
|
||||||
|
widgetName: Factory.each((i) => `Table${i + 1}`),
|
||||||
|
|
||||||
|
searchKey: "",
|
||||||
|
tableData:
|
||||||
|
'[\n {\n "id: 2381224,\n "email: "michael.lawson@reqres.in",\n "userName: "Michael Lawson",\n "productName: "Chicken Sandwich",\n "orderAmount: 4.99\n },\n {\n "id: 2736212,\n "email: "lindsay.ferguson@reqres.in",\n "userName: "Lindsay Ferguson",\n "productName: "Tuna Salad",\n "orderAmount: 9.99\n },\n {\n "id: 6788734,\n "email: "tobias.funke@reqres.in",\n "userName: "Tobias Funke",\n "productName: "Beef steak",\n "orderAmount: 19.99\n }\n]',
|
||||||
|
type: "TABLE_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 74,
|
||||||
|
parentRowSpace: 40,
|
||||||
|
leftColumn: 2,
|
||||||
|
rightColumn: 10,
|
||||||
|
topRow: 12,
|
||||||
|
bottomRow: 19,
|
||||||
|
parentId: "0",
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
primaryColumns: {
|
||||||
|
id: {
|
||||||
|
index: 0,
|
||||||
|
width: 150,
|
||||||
|
id: "id",
|
||||||
|
horizontalAlignment: "LEFT",
|
||||||
|
verticalAlignment: "CENTER",
|
||||||
|
columnType: "text",
|
||||||
|
textColor: "#4E5D78",
|
||||||
|
textSize: "PARAGRAPH",
|
||||||
|
fontStyle: "NORMAL",
|
||||||
|
enableFilter: true,
|
||||||
|
enableSort: true,
|
||||||
|
isVisible: true,
|
||||||
|
isDerived: false,
|
||||||
|
label: "id",
|
||||||
|
computedValue: "",
|
||||||
|
},
|
||||||
|
email: {
|
||||||
|
index: 1,
|
||||||
|
width: 150,
|
||||||
|
id: "email",
|
||||||
|
horizontalAlignment: "LEFT",
|
||||||
|
verticalAlignment: "CENTER",
|
||||||
|
columnType: "text",
|
||||||
|
textColor: "#4E5D78",
|
||||||
|
textSize: "PARAGRAPH",
|
||||||
|
fontStyle: "NORMAL",
|
||||||
|
enableFilter: true,
|
||||||
|
enableSort: true,
|
||||||
|
isVisible: true,
|
||||||
|
isDerived: false,
|
||||||
|
label: "email",
|
||||||
|
computedValue: "",
|
||||||
|
},
|
||||||
|
userName: {
|
||||||
|
index: 2,
|
||||||
|
width: 150,
|
||||||
|
id: "userName",
|
||||||
|
horizontalAlignment: "LEFT",
|
||||||
|
verticalAlignment: "CENTER",
|
||||||
|
columnType: "text",
|
||||||
|
textColor: "#4E5D78",
|
||||||
|
textSize: "PARAGRAPH",
|
||||||
|
fontStyle: "NORMAL",
|
||||||
|
enableFilter: true,
|
||||||
|
enableSort: true,
|
||||||
|
isVisible: true,
|
||||||
|
isDerived: false,
|
||||||
|
label: "userName",
|
||||||
|
computedValue: "",
|
||||||
|
},
|
||||||
|
productName: {
|
||||||
|
index: 3,
|
||||||
|
width: 150,
|
||||||
|
id: "productName",
|
||||||
|
horizontalAlignment: "LEFT",
|
||||||
|
verticalAlignment: "CENTER",
|
||||||
|
columnType: "text",
|
||||||
|
textColor: "#4E5D78",
|
||||||
|
textSize: "PARAGRAPH",
|
||||||
|
fontStyle: "NORMAL",
|
||||||
|
enableFilter: true,
|
||||||
|
enableSort: true,
|
||||||
|
isVisible: true,
|
||||||
|
isDerived: false,
|
||||||
|
label: "productName",
|
||||||
|
computedValue: "",
|
||||||
|
},
|
||||||
|
orderAmount: {
|
||||||
|
index: 4,
|
||||||
|
width: 150,
|
||||||
|
id: "orderAmount",
|
||||||
|
horizontalAlignment: "LEFT",
|
||||||
|
verticalAlignment: "CENTER",
|
||||||
|
columnType: "text",
|
||||||
|
textColor: "#4E5D78",
|
||||||
|
textSize: "PARAGRAPH",
|
||||||
|
fontStyle: "NORMAL",
|
||||||
|
enableFilter: true,
|
||||||
|
enableSort: true,
|
||||||
|
isVisible: true,
|
||||||
|
isDerived: false,
|
||||||
|
label: "orderAmount",
|
||||||
|
computedValue: "",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
145
app/client/test/factories/Widgets/TabsFactory.ts
Normal file
145
app/client/test/factories/Widgets/TabsFactory.ts
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const OldTabsFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
shouldScrollContents: false,
|
||||||
|
tabs: [
|
||||||
|
{
|
||||||
|
label: "Tab 1",
|
||||||
|
id: "tab1",
|
||||||
|
widgetId: "o9ody00ep7",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Tab 2",
|
||||||
|
id: "tab2",
|
||||||
|
widgetId: "plhuaxd4lo",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
shouldShowTabs: true,
|
||||||
|
defaultTab: "Tab 1",
|
||||||
|
type: "TABS_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 74,
|
||||||
|
parentRowSpace: 40,
|
||||||
|
leftColumn: 1,
|
||||||
|
rightColumn: 9,
|
||||||
|
topRow: 12,
|
||||||
|
bottomRow: 19,
|
||||||
|
parentId: "0",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
tabId: "tab1",
|
||||||
|
tabName: "Tab 1",
|
||||||
|
widgetId: "o9ody00ep7",
|
||||||
|
parentId: "jd83uvbkmp",
|
||||||
|
detachFromLayout: true,
|
||||||
|
children: [],
|
||||||
|
parentRowSpace: 1,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
leftColumn: 0,
|
||||||
|
rightColumn: 592,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 280,
|
||||||
|
isLoading: false,
|
||||||
|
widgetName: "Canvas1",
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
tabId: "tab2",
|
||||||
|
tabName: "Tab 2",
|
||||||
|
widgetId: "plhuaxd4lo",
|
||||||
|
parentId: "jd83uvbkmp",
|
||||||
|
detachFromLayout: true,
|
||||||
|
children: [],
|
||||||
|
parentRowSpace: 1,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
leftColumn: 0,
|
||||||
|
rightColumn: 592,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 280,
|
||||||
|
isLoading: false,
|
||||||
|
widgetName: "Canvas1",
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Tabs${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const TabsFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
shouldScrollContents: false,
|
||||||
|
tabsObj: {
|
||||||
|
tab1: {
|
||||||
|
label: "Tab 1",
|
||||||
|
id: "tab1",
|
||||||
|
widgetId: "o9ody00ep7",
|
||||||
|
},
|
||||||
|
tab2: {
|
||||||
|
label: "Tab 2",
|
||||||
|
id: "tab2",
|
||||||
|
widgetId: "plhuaxd4lo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
shouldShowTabs: true,
|
||||||
|
defaultTab: "Tab 1",
|
||||||
|
type: "TABS_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 74,
|
||||||
|
parentRowSpace: 40,
|
||||||
|
leftColumn: 1,
|
||||||
|
rightColumn: 9,
|
||||||
|
topRow: 12,
|
||||||
|
bottomRow: 19,
|
||||||
|
parentId: "0",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
tabId: "tab1",
|
||||||
|
tabName: "Tab 1",
|
||||||
|
widgetId: "o9ody00ep7",
|
||||||
|
parentId: "jd83uvbkmp",
|
||||||
|
detachFromLayout: true,
|
||||||
|
children: [],
|
||||||
|
parentRowSpace: 1,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
leftColumn: 0,
|
||||||
|
rightColumn: 592,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 280,
|
||||||
|
isLoading: false,
|
||||||
|
widgetName: "Canvas1",
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "CANVAS_WIDGET",
|
||||||
|
tabId: "tab2",
|
||||||
|
tabName: "Tab 2",
|
||||||
|
widgetId: "plhuaxd4lo",
|
||||||
|
parentId: "jd83uvbkmp",
|
||||||
|
detachFromLayout: true,
|
||||||
|
children: [],
|
||||||
|
parentRowSpace: 1,
|
||||||
|
parentColumnSpace: 1,
|
||||||
|
leftColumn: 0,
|
||||||
|
rightColumn: 592,
|
||||||
|
topRow: 0,
|
||||||
|
bottomRow: 280,
|
||||||
|
isLoading: false,
|
||||||
|
widgetName: "Canvas1",
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Tabs${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
31
app/client/test/factories/Widgets/TextFactory.ts
Normal file
31
app/client/test/factories/Widgets/TextFactory.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const TextFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
widgetName: Factory.each((i) => `Text${(i+1)}`),
|
||||||
|
rightColumn: 12,
|
||||||
|
onClick: "",
|
||||||
|
isDefaultClickDisabled: true,
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
buttonStyle: "PRIMARY_BUTTON",
|
||||||
|
topRow: 1,
|
||||||
|
bottomRow: 2,
|
||||||
|
parentRowSpace: 38,
|
||||||
|
isVisible: true,
|
||||||
|
type: "BUTTON_WIDGET",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
parentId: "0",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 34.6875,
|
||||||
|
leftColumn: 10,
|
||||||
|
dynamicTriggerPathList: [
|
||||||
|
{
|
||||||
|
key: "onClick",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
text: "Test Button Text",
|
||||||
|
isDisabled: false,
|
||||||
|
version: 1,
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
});
|
||||||
23
app/client/test/factories/Widgets/VideoFactory.ts
Normal file
23
app/client/test/factories/Widgets/VideoFactory.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
import * as Factory from "factory.ts";
|
||||||
|
import { generateReactKey } from "utils/generators";
|
||||||
|
import { WidgetProps } from "widgets/BaseWidget";
|
||||||
|
|
||||||
|
export const VideoFactory = Factory.Sync.makeFactory<WidgetProps>({
|
||||||
|
isVisible: true,
|
||||||
|
url: "https://www.youtube.com/watch?v=mzqK0QIZRLs",
|
||||||
|
autoPlay: false,
|
||||||
|
type: "VIDEO_WIDGET",
|
||||||
|
isLoading: false,
|
||||||
|
parentColumnSpace: 74,
|
||||||
|
parentRowSpace: 40,
|
||||||
|
leftColumn: 1,
|
||||||
|
rightColumn: 8,
|
||||||
|
topRow: 17,
|
||||||
|
bottomRow: 24,
|
||||||
|
parentId: "0",
|
||||||
|
dynamicBindingPathList: [],
|
||||||
|
widgetName: Factory.each((i) => `Video${i + 1}`),
|
||||||
|
widgetId: generateReactKey(),
|
||||||
|
renderMode: "CANVAS",
|
||||||
|
version: 1,
|
||||||
|
});
|
||||||
53
app/client/test/factories/Widgets/WidgetTypeFactories.ts
Normal file
53
app/client/test/factories/Widgets/WidgetTypeFactories.ts
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
import { SwitchFactory } from "./SwitchFactory";
|
||||||
|
import { ButtonFactory } from "./ButtonFactory";
|
||||||
|
import { TextFactory } from "./TextFactory";
|
||||||
|
import { ImageFactory } from "./ImageFactory";
|
||||||
|
import { InputFactory } from "./InputFactory";
|
||||||
|
import { TableFactory } from "./TableFactory";
|
||||||
|
import { OldDatepickerFactory, DatepickerFactory } from "./DatepickerFactory";
|
||||||
|
import { ContainerFactory } from "./ContainerFactory";
|
||||||
|
import { DropdownFactory } from "./DropdownFactory";
|
||||||
|
import { CheckboxFactory } from "./CheckboxFactory";
|
||||||
|
import { RadiogroupFactory } from "./RadiogroupFactory";
|
||||||
|
import { OldTabsFactory, TabsFactory } from "./TabsFactory";
|
||||||
|
import { ModalFactory } from "./ModalFactory";
|
||||||
|
import { RichTextFactory } from "./RichTextFactory";
|
||||||
|
import { ChartFactory } from "./ChartFactory";
|
||||||
|
import { FormFactory } from "./FormFactory";
|
||||||
|
import { FormButtonFactory } from "./FormButtonFactory";
|
||||||
|
import { MapFactory } from "./MapFactory";
|
||||||
|
import { CanvasFactory } from "./CanvasFactory";
|
||||||
|
import { IconFactory } from "./IconFactory";
|
||||||
|
import { FilepickerFactory } from "./FilepickerFactory";
|
||||||
|
import { VideoFactory } from "./VideoFactory";
|
||||||
|
import { SkeletonFactory } from "./SkeletonFactory";
|
||||||
|
import { ListFactory } from "./ListFactory";
|
||||||
|
|
||||||
|
export const WidgetTypeFactories = {
|
||||||
|
SWITCH_WIDGET: SwitchFactory,
|
||||||
|
BUTTON_WIDGET: ButtonFactory,
|
||||||
|
TEXT_WIDGET: TextFactory,
|
||||||
|
IMAGE_WIDGET: ImageFactory,
|
||||||
|
INPUT_WIDGET: InputFactory,
|
||||||
|
CONTAINER_WIDGET: ContainerFactory,
|
||||||
|
DATE_PICKER_WIDGET: OldDatepickerFactory,
|
||||||
|
DATE_PICKER_WIDGET2: DatepickerFactory,
|
||||||
|
TABLE_WIDGET: TableFactory,
|
||||||
|
DROP_DOWN_WIDGET: DropdownFactory,
|
||||||
|
CHECKBOX_WIDGET: CheckboxFactory,
|
||||||
|
RADIO_GROUP_WIDGET: RadiogroupFactory,
|
||||||
|
TABS_WIDGET: TabsFactory,
|
||||||
|
TABS_MIGRATOR_WIDGET: OldTabsFactory,
|
||||||
|
MODAL_WIDGET: ModalFactory,
|
||||||
|
RICH_TEXT_EDITOR_WIDGET: RichTextFactory,
|
||||||
|
CHART_WIDGET: ChartFactory,
|
||||||
|
FORM_WIDGET: FormFactory,
|
||||||
|
FORM_BUTTON_WIDGET: FormButtonFactory,
|
||||||
|
MAP_WIDGET: MapFactory,
|
||||||
|
CANVAS_WIDGET: CanvasFactory,
|
||||||
|
ICON_WIDGET: IconFactory,
|
||||||
|
FILE_PICKER_WIDGET: FilepickerFactory,
|
||||||
|
VIDEO_WIDGET: VideoFactory,
|
||||||
|
SKELETON_WIDGET: SkeletonFactory,
|
||||||
|
LIST_WIDGET: ListFactory,
|
||||||
|
};
|
||||||
|
|
@ -7,6 +7,8 @@ import { getCurrentThemeDetails } from "../src/selectors/themeSelectors";
|
||||||
import * as customQueries from "./customQueries";
|
import * as customQueries from "./customQueries";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import { AppState } from "reducers";
|
import { AppState } from "reducers";
|
||||||
|
import { DndProvider } from "react-dnd";
|
||||||
|
import TouchBackend from "react-dnd-touch-backend";
|
||||||
|
|
||||||
const customRender = (
|
const customRender = (
|
||||||
ui: ReactElement,
|
ui: ReactElement,
|
||||||
|
|
@ -25,7 +27,14 @@ const customRender = (
|
||||||
return render(
|
return render(
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Provider store={reduxStore}>
|
<Provider store={reduxStore}>
|
||||||
|
<DndProvider
|
||||||
|
backend={TouchBackend}
|
||||||
|
options={{
|
||||||
|
enableMouseEvents: true,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ThemeProvider theme={defaultTheme}>{ui}</ThemeProvider>
|
<ThemeProvider theme={defaultTheme}>{ui}</ThemeProvider>
|
||||||
|
</DndProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
</BrowserRouter>,
|
</BrowserRouter>,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -8162,6 +8162,14 @@ extsprintf@^1.2.0:
|
||||||
version "1.4.0"
|
version "1.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||||
|
|
||||||
|
factory.ts@^0.5.1:
|
||||||
|
version "0.5.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/factory.ts/-/factory.ts-0.5.1.tgz#4bab72d8457078906aa6ab396c0d341e8a3ab382"
|
||||||
|
integrity sha512-jwAq8w7MmxUojIFzKezMwTzDc5QoxcqzAA8+n9A0EAWBje2CRHUeBrW9x/ioV2DRjHgkHX7i0G0ipfDhlatIQw==
|
||||||
|
dependencies:
|
||||||
|
clone-deep "^4.0.1"
|
||||||
|
source-map-support "^0.5.9"
|
||||||
|
|
||||||
fast-deep-equal@^2.0.1:
|
fast-deep-equal@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||||
|
|
@ -15637,7 +15645,7 @@ source-map-resolve@^0.6.0:
|
||||||
atob "^2.1.2"
|
atob "^2.1.2"
|
||||||
decode-uri-component "^0.2.0"
|
decode-uri-component "^0.2.0"
|
||||||
|
|
||||||
source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.19:
|
source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@^0.5.9, source-map-support@~0.5.12, source-map-support@~0.5.19:
|
||||||
version "0.5.19"
|
version "0.5.19"
|
||||||
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user