feat: dsl migration with server (#28518)

## Description
1. Shifts DSL migration logic to @shared/dsl
2. Exposes /migrate/dsl endpoint on rts
3. Integrates RTS endpoint to backend for serving migrated pages
4. Introduces feature flag to switch between client-based and
server-based on-demand migration

#### PR fixes following issue(s)
Fixes #26783, #26784, #26980 

#### Type of change
- New feature (non-breaking change which adds functionality)

## Testing
>
#### How Has This Been Tested?
> Please describe the tests that you ran to verify your changes. Also
list any relevant details for your test configuration.
> Delete anything that is not relevant
- [x] Manual
- [ ] JUnit
- [x] Jest
- [x] Cypress
>
>
#### Test Plan
> Add Testsmith test cases links that relate to this PR
>
>
#### Issues raised during DP testing
> Link issues raised during DP testing for better visiblity and tracking
(copy link from comments dropped on this PR)
>
>
>
## Checklist:
#### Dev activity
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] PR is being merged under a feature flag


#### QA activity:
- [ ] [Speedbreak
features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-)
have been covered
- [ ] Test plan covers all impacted features and [areas of
interest](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#areas-of-interest-)
- [ ] Test plan has been peer reviewed by project stakeholders and other
QA members
- [ ] Manually tested functionality on DP
- [ ] We had an implementation alignment call with stakeholders post QA
Round 2
- [ ] Cypress test cases have been added and approved by SDET/manual QA
- [ ] Added `Test Plan Approved` label after Cypress tests were reviewed
- [ ] Added `Test Plan Approved` label after JUnit tests were reviewed

---------

Co-authored-by: Nayan <nayan@appsmith.com>
This commit is contained in:
Rudraprasad Das 2023-11-30 18:03:33 +05:30 committed by GitHub
parent e018db8ec7
commit 71d67185c4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
147 changed files with 74237 additions and 3503 deletions

View File

@ -116,8 +116,10 @@ app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitCloudSer
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitDeployKeyGenerator.java @AnaghHegde @nayan-rafiq
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitFileUtils.java @AnaghHegde @nayan-rafiq
app/server/appsmith-server/src/main/java/com/appsmith/server/helpers/GitUtils.java @AnaghHegde @nayan-rafiq
app/client/src/pages/Editor/gitSync/* @brayn003
# DSL Package
app/client/packages/dsl/* @brayn003
# Data Platform
@ -215,7 +217,7 @@ app/client/cypress/e2e/Regression/ClientSide/Github/**/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/FormLogin/**/* @ankitakinger
app/client/cypress/e2e/Regression/ClientSide/Auditlogs/**/* @ankitakinger
#FE pod
# FE pod
app/client/src/actions/evaluationActions.ts @ApekshaBhosale
app/client/src/ce/entities/DataTree/**/* @ApekshaBhosale
app/client/src/ce/entities/DependencyMap/**/* @ApekshaBhosale

View File

@ -20,7 +20,6 @@ describe("Check debugger logs state when there are onPageLoad actions", function
it("1. Check debugger logs state when there are onPageLoad actions", function () {
EditorNavigation.SelectEntityByName("Table1", EntityType.Widget);
propPane.UpdatePropertyFieldValue("Table data", "{{TestApi.data.users}}");
apiPage.CreateAndFillApi(testdata.baseUrl + testdata.methods, "TestApi");
apiPage.RunAPI();
agHelper.GetNClick(explorer.addWidget);

View File

@ -62,7 +62,6 @@ describe("Input widget test with default value from chart datapoint", () => {
it("2. onDataPointClick should work and respond with x, y, seriesTitle, and rawEventData (in case of custom fusion chart).", () => {
agHelper.AddDsl("chartCustomSankeyDataDsl");
assertHelper.AssertNetworkStatus("@updateLayout");
EditorNavigation.SelectEntityByName("Chart1", EntityType.Widget);
agHelper.Sleep(1500); //waiting for chart to load!
propPane.SelectPlatformFunction("onDataPointClick", "Show alert");

View File

@ -120,7 +120,6 @@ describe("DatePicker Widget Property pane tests with js bindings", function () {
EditorNavigation.SelectEntityByName("DatePicker1", EntityType.Widget);
_.propPane.EnterJSContext("Min Date", "2021-01-01");
_.propPane.EnterJSContext("Max Date", "2021-10-10");
_.propPane.EnterJSContext("Default Date", "");
cy.selectDateFormat("DD/MM/YYYY HH:mm");
_.propPane.EnterJSContext(
"Default Date",

View File

@ -6,11 +6,6 @@ describe("Form data", function () {
});
it("CheckboxGroupWidget, MultiSelectTreeWidget, MultiSelectWidgetV2, SelectWidget, SingleSelectTreeWidget, SwitchGroupWidget, PhoneInputWidget, InputWidgetV2 and CurrencyInputWidget should have value props of which values are not null or undefined to be included as a form data", function () {
cy.wait("@updateLayout").should(
"have.nested.property",
"response.body.responseMeta.status",
200,
);
// Check form data
cy.get("[data-testid='container-wrapper-vannrar7rd'] span")
.should("exist")

View File

@ -15,7 +15,6 @@ describe("Table Widget Filtered Table data in autocomplete", function () {
it("Table Widget Functionality To Filter and search data", function () {
cy.openPropertyPane("tablewidget");
cy.wait("@updateLayout");
cy.get(publish.searchInput).first().type("query");
cy.get(publish.filterBtn).click();
cy.get(publish.attributeDropdown).click();

View File

@ -12,7 +12,7 @@ describe("Basic flow ", () => {
cy.get(".t--property-control-allowaddingarow").should("exist");
cy.get(".t--property-control-allowaddingarow input").should("exist");
cy.get(".t--add-new-row").should("not.exist");
_.propPane.TogglePropertyState("Allow adding a row", "Off");
_.propPane.TogglePropertyState("Allow adding a row", "Off", null);
cy.get(".t--add-new-row").should("not.exist");
cy.get(".t--property-control-onsave").should("not.exist");
cy.get(".t--property-control-ondiscard").should("not.exist");

View File

@ -13,7 +13,6 @@ describe("Table Widget V2 Filtered Table data in autocomplete", function () {
before("Table Widget V2 Functionality", () => {
_.agHelper.AddDsl("tableV2AndTextDsl");
cy.openPropertyPane("tablewidgetv2");
cy.wait("@updateLayout");
});
it("1. Table Widget V2 Functionality To Filter and search data", function () {

View File

@ -1,4 +1,9 @@
{
"extends": ["../../.eslintrc.base.json"],
"ignorePatterns": ["build"]
"ignorePatterns": ["build"],
"rules": {
"@typescript-eslint/strict-boolean-expressions": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/prefer-nullish-coalescing": "off"
}
}

View File

@ -24,6 +24,7 @@
"typescript": "4.5.5"
},
"devDependencies": {
"@rollup/plugin-json": "^6.0.0",
"jest": "^29.5.0",
"ts-jest": "^29.1.0"
}

View File

@ -3,6 +3,7 @@ import commonjs from "@rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import generatePackageJson from "rollup-plugin-generate-package-json";
import packageJson from "./package.json";
import json from "@rollup/plugin-json";
export default {
// TODO: Figure out regex where each directory can be a separate module without having to manually add them
@ -25,6 +26,7 @@ export default {
typescript({
useTsconfigDeclarationDir: true,
}),
json(),
generatePackageJson({
baseContents: (pkg) => ({
...pkg,

View File

@ -1,5 +1,4 @@
export { nestDSL, flattenDSL } from "./DSL";
export { ROOT_CONTAINER_WIDGET_ID } from "./constants";
export { nestDSL, flattenDSL, ROOT_CONTAINER_WIDGET_ID } from "./transform";
export type {
NestedDSLWidget,
@ -7,4 +6,8 @@ export type {
FlattenedDSLWidget,
FlattenedDSL,
FlattenedDSLEntities,
} from "./DSL";
} from "./transform";
export { migrateDSL, LATEST_DSL_VERSION } from "./migrate";
export type { DSLWidget } from "./migrate/types";

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,599 @@
import { flattenDSL } from "../transform";
import { updateContainers } from "./migrations/001-update-containers";
import { chartDataMigration } from "./migrations/002-chart-data-migration";
import { mapDataMigration } from "./migrations/003-map-data-migration";
import { singleChartDataMigration } from "./migrations/004-single-chart-data-migration";
import { tabsWidgetTabsPropertyMigration } from "./migrations/005-tabs-widget-property-migration";
import { dynamicPathListMigration } from "./migrations/006-dynamic-path-list-migration";
import { canvasNameConflictMigration } from "./migrations/007-canvas-name-conflict-migration";
import { renamedCanvasNameConflictMigration } from "./migrations/008-renamed-canvas-name-conflict-migration";
import { tableWidgetPropertyPaneMigrations } from "./migrations/009-table-widget-property-pane-migration";
import { addVersionNumberMigration } from "./migrations/010-add-version-number-migration";
import { migrateTablePrimaryColumnsBindings } from "./migrations/011-migrate-table-primary-columns-binding";
import { migrateIncorrectDynamicBindingPathLists } from "./migrations/012-migrate-incorrect-dynamic-binding-path-lists";
import { migrateOldChartData } from "./migrations/013-migrate-old-chart-data";
import { rteDefaultValueMigration } from "./migrations/014-rte-default-value-migration";
import { migrateTextStyleFromTextWidget } from "./migrations/015-migrate-text-style-from-text-widget";
import { migrateChartDataFromArrayToObject } from "./migrations/016-migrate-chart-data-from-array-to-object";
import { migrateTabsData } from "./migrations/017-migrate-tabs-data";
import { migrateInitialValues } from "./migrations/018-migrate-initial-values";
import {
getCanvasSnapRows,
migrateToNewLayout,
} from "./migrations/019-migrate-to-new-layout";
import { migrateNewlyAddedTabsWidgetsMissingData } from "./migrations/020-migrate-newly-added-tabs-widgets-missing-data";
import {
migrateOverFlowingTabsWidgets,
migrateWidgetsWithoutLeftRightColumns,
} from "./migrations/021-migrate-overflowing-tabs-widgets";
import { migrateTableWidgetParentRowSpaceProperty } from "./migrations/022-migrate-table-widget-parent-row-space-property";
import { addLogBlackListToAllListWidgetChildren } from "./migrations/023-add-log-blacklist-to-all-widget-children";
import { migrateTableWidgetHeaderVisibilityProperties } from "./migrations/024-migrate-table-widget-header-visibility-properties";
import { migrateItemsToListDataInListWidget } from "./migrations/025-migrate-items-to-list-data-in-list-widget";
import { migrateDatePickerMinMaxDate } from "./migrations/026-migrate-datepicker-min-max-date";
import { migrateFilterValueForDropDownWidget } from "./migrations/027-migrate-filter-value-for-dropdown-widget";
import { migrateTablePrimaryColumnsComputedValue } from "./migrations/028-migrate-table-primary-columns-computed-value";
import { migrateToNewMultiSelect } from "./migrations/029-migrate-to-new-multiselect";
import { migrateTableWidgetDelimiterProperties } from "./migrations/030-migrate-table-widget-delimiter-properties";
import { migrateIsDisabledToButtonColumn } from "./migrations/031-migrate-is-disabled-to-button-column";
import { migrateTableDefaultSelectedRow } from "./migrations/032-migrate-table-default-selected-row";
import { migrateMenuButtonWidgetButtonProperties } from "./migrations/033-migrate-menu-button-widget-button-properties";
import { migrateButtonWidgetValidation } from "./migrations/034-migrate-button-widget-validation";
import { migrateInputValidation } from "./migrations/035-migrate-input-validation";
import { revertTableDefaultSelectedRow } from "./migrations/036-revert-table-default-selected-row";
import { migrateTableSanitizeColumnKeys } from "./migrations/037-migrate-table-sanitize-column-keys";
import { migrateResizableModalWidgetProperties } from "./migrations/038-migrate-resizable-modal-widget-properties";
import { migrateTableWidgetSelectedRowBindings } from "./migrations/039-migrate-table-widget-selected-row-bindings";
import { revertButtonStyleToButtonColor } from "./migrations/040-revert-button-style-to-button-color";
import { migrateButtonVariant } from "./migrations/041-migrate-button-variant";
import { migrateMapWidgetIsClickedMarkerCentered } from "./migrations/042-migrate-map-widget-is-clicked-marker-centered";
import { mapAllowHorizontalScrollMigration } from "./migrations/043-map-allow-horizontal-scroll-mirgation";
import { isSortableMigration } from "./migrations/044-is-sortable-migration";
import { migrateTableWidgetIconButtonVariant } from "./migrations/045-migrate-table-widget-icon-button-variant";
import { migrateCheckboxGroupWidgetInlineProperty } from "./migrations/046-migrate-checkbox-group-widget-inline-property";
import { migrateRecaptchaType } from "./migrations/048-migrate-recaptcha-type";
import { addPrivateWidgetsToAllListWidgets } from "./migrations/049-add-private-widgets-to-all-list-widgets";
import { migratePhoneInputWidgetAllowFormatting } from "./migrations/051-migrate-phone-input-widget-allow-formatting";
import { migrateModalIconButtonWidget } from "./migrations/052-migrate-modal-icon-button-widget";
import { migrateScrollTruncateProperties } from "./migrations/053-migrate-scroll-truncate-property";
import { migratePhoneInputWidgetDefaultDialCode } from "./migrations/054-migrate-phone-input-widget-default-dial-code";
import { migrateCurrencyInputWidgetDefaultCurrencyCode } from "./migrations/055-migrate-currency-input-widget-default-currency-code";
import { migrateRadioGroupAlignmentProperty } from "./migrations/056-migrate-radio-group-alignment-property";
import { migrateStylingPropertiesForTheming } from "./migrations/057-migrate-styling-properties-for-theming";
import { migrateCheckboxSwitchProperty } from "./migrations/058-migrate-checkbox-switch-property";
import { migrateChartWidgetReskinningData } from "./migrations/059-migrate-chart-widget-reskinning-data";
import { migrateTableWidgetV2Validation } from "./migrations/060-migrate-table-widget-v2-validation";
import { MigrateSelectTypeWidgetDefaultValue } from "./migrations/062-migrate-select-type-widget-default-value";
import { migrateMapChartWidgetReskinningData } from "./migrations/063-migrate-map-chart-widget-reskinning-data";
import { migrateRateWidgetDisabledState } from "./migrations/064-migrate-rate-widget-disabed-state";
import { migrateCodeScannerLayout } from "./migrations/065-migrate-code-scanner-layout";
import { migrateTableWidgetV2ValidationBinding } from "./migrations/066-migrate-table-widget-v2-validation-binding";
import { migrateLabelPosition } from "./migrations/067-migrate-label-position";
import { migratePropertiesForDynamicHeight } from "./migrations/068-migrate-properties-for-dynamic-height";
import { migrateMenuButtonDynamicItems } from "./migrations/069-migrate-menu-button-dynamic-items";
import { migrateChildStylesheetFromDynamicBindingPathList } from "./migrations/070-migrate-child-stylesheet-from-dynamic-binding-path-list";
import { migrateTableWidgetV2SelectOption } from "./migrations/071-migrate-table-widget-v2-select-option";
import { migrateListWidgetChildrenForAutoHeight } from "./migrations/072-migrate-list-widget-children-for-auto-height";
import { migrateInputWidgetShowStepArrows } from "./migrations/073-mirgate-input-widget-show-step-arrows";
import { migrateMenuButtonDynamicItemsInsideTableWidget } from "./migrations/074-migrate-mwnu-button-dynamic-items-inside-table-widget";
import { migrateInputWidgetsMultiLineInputType } from "./migrations/075-migrate-input-widgets-multiline-input-type";
import { migrateColumnFreezeAttributes } from "./migrations/076-migrate-column-freeze-attributes";
import { migrateTableSelectOptionAttributesForNewRow } from "./migrations/077-migrate-table-select-option-attributes-for-new-row";
import { migrateBindingPrefixSuffixForInlineEditValidationControl } from "./migrations/078-migrate-binding-prefix-suffix-for-inline-edit-validation-control";
import { migrateTableWidgetTableDataJsMode } from "./migrations/079-migrate-table-widget-table-data-js-mode";
import { migrateSelectWidgetOptionToSourceData } from "./migrations/080-migrate-select-widget-option-to-source-data";
import { migrateSelectWidgetSourceDataBindingPathList } from "./migrations/081-migrate-select-widget-source-data-binding-path-list";
import { migrateChartWidgetLabelOrientationStaggerOption } from "./migrations/082-migrate-chart-widget-label-orientation-stagger-option";
import { migrateAddShowHideDataPointLabels } from "./migrations/083-migrate-add-show-hide-data-point-labels";
import { migrateSelectWidgetAddSourceDataPropertyPathList } from "./migrations/084-migrate-select-widget-add-source-data-property-path-list";
import { migrateDefaultValuesForCustomEChart } from "./migrations/085-migrate-default-values-for-custom-echart";
import { migrateTableServerSideFiltering } from "./migrations/086-migrate-table-server-side-filtering";
import type { DSLWidget } from "./types";
export const LATEST_DSL_VERSION = 87;
export const calculateDynamicHeight = () => {
const DEFAULT_GRID_ROW_HEIGHT = 10;
const screenHeight = typeof window !== "undefined" ? window.innerHeight : 600;
const gridRowHeight = DEFAULT_GRID_ROW_HEIGHT;
// DGRH - DEFAULT_GRID_ROW_HEIGHT
// View Mode: Header height + Page Selection Tab = 8 * DGRH (approx)
// Edit Mode: Header height + Canvas control = 8 * DGRH (approx)
// buffer: ~8 grid row height
const buffer =
gridRowHeight +
2 * 48 /*pixelToNumber(theme.smallHeaderHeight) */ +
37; /*pixelToNumber(theme.bottomBarHeight);*/
const calculatedMinHeight =
Math.floor((screenHeight - buffer) / gridRowHeight) * gridRowHeight;
return calculatedMinHeight;
};
const migrateUnversionedDSL = (currentDSL: DSLWidget) => {
const DEFAULT_GRID_ROW_HEIGHT = 10;
if (currentDSL.version === undefined) {
// Since this top level widget is a CANVAS_WIDGET,
// DropTargetComponent needs to know the minimum height the canvas can take
// See DropTargetUtils.ts
currentDSL.minHeight = calculateDynamicHeight();
currentDSL.bottomRow = currentDSL.minHeight - DEFAULT_GRID_ROW_HEIGHT;
// For the first time the DSL is created, remove one row from the total possible rows
// to adjust for padding and margins.
currentDSL.snapRows =
Math.floor(currentDSL.bottomRow / DEFAULT_GRID_ROW_HEIGHT) - 1;
// Force the width of the canvas to 1224 px
currentDSL.rightColumn = 1224;
// The canvas is a CANVAS_WIDGET which doesn't have a background or borders by default
currentDSL.backgroundColor = "none";
currentDSL.containerStyle = "none";
currentDSL.type = "CANVAS_WIDGET";
currentDSL.detachFromLayout = true;
currentDSL.canExtend = true;
// Update version to make sure this doesn't run every time.
currentDSL.version = 1;
}
return currentDSL;
};
// A rudimentary transform function which updates the DSL based on its version.
// A more modular approach needs to be designed.
// This needs the widget config to be already built to migrate correctly
const migrateVersionedDSL = (currentDSL: DSLWidget, newPage = false) => {
if (currentDSL.version === 1) {
if (currentDSL.children && currentDSL.children.length > 0)
currentDSL.children = currentDSL.children.map(updateContainers);
currentDSL.version = 2;
}
if (currentDSL.version === 2) {
currentDSL = chartDataMigration(currentDSL);
currentDSL.version = 3;
}
if (currentDSL.version === 3) {
currentDSL = mapDataMigration(currentDSL);
currentDSL.version = 4;
}
if (currentDSL.version === 4) {
currentDSL = singleChartDataMigration(currentDSL);
currentDSL.version = 5;
}
if (currentDSL.version === 5) {
currentDSL = tabsWidgetTabsPropertyMigration(currentDSL);
currentDSL.version = 6;
}
if (currentDSL.version === 6) {
currentDSL = dynamicPathListMigration(currentDSL);
currentDSL.version = 7;
}
if (currentDSL.version === 7) {
currentDSL = canvasNameConflictMigration(currentDSL);
currentDSL.version = 8;
}
if (currentDSL.version === 8) {
currentDSL = renamedCanvasNameConflictMigration(currentDSL);
currentDSL.version = 9;
}
if (currentDSL.version === 9) {
currentDSL = tableWidgetPropertyPaneMigrations(currentDSL);
currentDSL.version = 10;
}
if (currentDSL.version === 10) {
currentDSL = addVersionNumberMigration(currentDSL);
currentDSL.version = 11;
}
if (currentDSL.version === 11) {
currentDSL = migrateTablePrimaryColumnsBindings(currentDSL);
currentDSL.version = 12;
}
if (currentDSL.version === 12) {
currentDSL = migrateIncorrectDynamicBindingPathLists(currentDSL);
currentDSL.version = 13;
}
if (currentDSL.version === 13) {
currentDSL = migrateOldChartData(currentDSL);
currentDSL.version = 14;
}
if (currentDSL.version === 14) {
currentDSL = rteDefaultValueMigration(currentDSL);
currentDSL.version = 15;
}
if (currentDSL.version === 15) {
currentDSL = migrateTextStyleFromTextWidget(currentDSL);
currentDSL.version = 16;
}
if (currentDSL.version === 16) {
currentDSL = migrateChartDataFromArrayToObject(currentDSL);
currentDSL.version = 17;
}
if (currentDSL.version === 17) {
currentDSL = migrateTabsData(currentDSL);
currentDSL.version = 18;
}
if (currentDSL.version === 18) {
currentDSL = migrateInitialValues(currentDSL);
currentDSL.version = 19;
}
if (currentDSL.version === 19) {
currentDSL.snapColumns = 64; // GridDefaults.DEFAULT_GRID_COLUMNS;
currentDSL.snapRows = getCanvasSnapRows(currentDSL.bottomRow);
if (!newPage) {
currentDSL = migrateToNewLayout(currentDSL);
}
currentDSL.version = 20;
}
if (currentDSL.version === 20) {
currentDSL = migrateNewlyAddedTabsWidgetsMissingData(currentDSL);
currentDSL.version = 21;
}
if (currentDSL.version === 21) {
const canvasWidgets = flattenDSL(currentDSL);
currentDSL = migrateWidgetsWithoutLeftRightColumns(
currentDSL,
canvasWidgets,
);
currentDSL = migrateOverFlowingTabsWidgets(currentDSL, canvasWidgets);
currentDSL.version = 22;
}
if (currentDSL.version === 22) {
currentDSL = migrateTableWidgetParentRowSpaceProperty(currentDSL);
currentDSL.version = 23;
}
if (currentDSL.version === 23) {
currentDSL = addLogBlackListToAllListWidgetChildren(currentDSL);
currentDSL.version = 24;
}
if (currentDSL.version === 24) {
currentDSL = migrateTableWidgetHeaderVisibilityProperties(currentDSL);
currentDSL.version = 25;
}
if (currentDSL.version === 25) {
currentDSL = migrateItemsToListDataInListWidget(currentDSL);
currentDSL.version = 26;
}
if (currentDSL.version === 26) {
currentDSL = migrateDatePickerMinMaxDate(currentDSL);
currentDSL.version = 27;
}
if (currentDSL.version === 27) {
currentDSL = migrateFilterValueForDropDownWidget(currentDSL);
currentDSL.version = 28;
}
if (currentDSL.version === 28) {
currentDSL = migrateTablePrimaryColumnsComputedValue(currentDSL);
currentDSL.version = 29;
}
if (currentDSL.version === 29) {
currentDSL = migrateToNewMultiSelect(currentDSL);
currentDSL.version = 30;
}
if (currentDSL.version === 30) {
currentDSL = migrateTableWidgetDelimiterProperties(currentDSL);
currentDSL.version = 31;
}
if (currentDSL.version === 31) {
currentDSL = migrateIsDisabledToButtonColumn(currentDSL);
currentDSL.version = 32;
}
if (currentDSL.version === 32) {
currentDSL = migrateTableDefaultSelectedRow(currentDSL);
currentDSL.version = 33;
}
if (currentDSL.version === 33) {
currentDSL = migrateMenuButtonWidgetButtonProperties(currentDSL);
currentDSL.version = 34;
}
if (currentDSL.version === 34) {
currentDSL = migrateButtonWidgetValidation(currentDSL);
currentDSL.version = 35;
}
if (currentDSL.version === 35) {
currentDSL = migrateInputValidation(currentDSL);
currentDSL.version = 36;
}
if (currentDSL.version === 36) {
currentDSL = revertTableDefaultSelectedRow(currentDSL);
currentDSL.version = 37;
}
if (currentDSL.version === 37) {
currentDSL = migrateTableSanitizeColumnKeys(currentDSL);
currentDSL.version = 38;
}
if (currentDSL.version === 38) {
currentDSL = migrateResizableModalWidgetProperties(currentDSL);
currentDSL.version = 39;
}
if (currentDSL.version === 39) {
currentDSL = migrateTableWidgetSelectedRowBindings(currentDSL);
currentDSL.version = 40;
}
if (currentDSL.version === 40) {
currentDSL = revertButtonStyleToButtonColor(currentDSL);
currentDSL.version = 41;
}
if (currentDSL.version === 41) {
currentDSL = migrateButtonVariant(currentDSL);
currentDSL.version = 42;
}
if (currentDSL.version === 42) {
currentDSL = migrateMapWidgetIsClickedMarkerCentered(currentDSL);
currentDSL.version = 43;
}
if (currentDSL.version === 43) {
currentDSL = mapAllowHorizontalScrollMigration(currentDSL);
currentDSL.version = 44;
}
if (currentDSL.version === 44) {
currentDSL = isSortableMigration(currentDSL);
currentDSL.version = 45;
}
if (currentDSL.version === 45) {
currentDSL = migrateTableWidgetIconButtonVariant(currentDSL);
currentDSL.version = 46;
}
if (currentDSL.version === 46) {
currentDSL = migrateCheckboxGroupWidgetInlineProperty(currentDSL);
currentDSL.version = 47;
}
if (currentDSL.version === 47) {
// We're skipping this to fix a bad table migration.
// skipped migration is added as version 51
currentDSL.version = 48;
}
if (currentDSL.version === 48) {
currentDSL = migrateRecaptchaType(currentDSL);
currentDSL.version = 49;
}
if (currentDSL.version === 49) {
currentDSL = addPrivateWidgetsToAllListWidgets(currentDSL);
currentDSL.version = 50;
}
if (currentDSL.version === 50) {
/*
* We're skipping this to fix a bad table migration - migrateTableWidgetNumericColumnName
* it overwrites the computedValue of the table columns
*/
currentDSL.version = 51;
}
if (currentDSL.version === 51) {
currentDSL = migratePhoneInputWidgetAllowFormatting(currentDSL);
currentDSL.version = 52;
}
if (currentDSL.version === 52) {
currentDSL = migrateModalIconButtonWidget(currentDSL);
currentDSL.version = 53;
}
if (currentDSL.version === 53) {
currentDSL = migrateScrollTruncateProperties(currentDSL);
currentDSL.version = 54;
}
if (currentDSL.version === 54) {
currentDSL = migratePhoneInputWidgetDefaultDialCode(currentDSL);
currentDSL.version = 55;
}
if (currentDSL.version === 55) {
currentDSL = migrateCurrencyInputWidgetDefaultCurrencyCode(currentDSL);
currentDSL.version = 56;
}
if (currentDSL.version === 56) {
currentDSL = migrateRadioGroupAlignmentProperty(currentDSL);
currentDSL.version = 57;
}
if (currentDSL.version === 57) {
currentDSL = migrateStylingPropertiesForTheming(currentDSL);
currentDSL.version = 58;
}
if (currentDSL.version === 58) {
currentDSL = migrateCheckboxSwitchProperty(currentDSL);
currentDSL.version = 59;
}
if (currentDSL.version === 59) {
/**
* migrateChartWidgetReskinningData function will be executed again in version 61,
* since for older apps the accentColor and fontFamily didn't get migrated.
*/
currentDSL = migrateChartWidgetReskinningData(currentDSL);
currentDSL.version = 60;
}
if (currentDSL.version === 60) {
currentDSL = migrateTableWidgetV2Validation(currentDSL);
currentDSL.version = 61;
}
if (currentDSL.version === 61) {
currentDSL = migrateChartWidgetReskinningData(currentDSL);
currentDSL.version = 62;
}
if (currentDSL.version === 62) {
currentDSL = MigrateSelectTypeWidgetDefaultValue(currentDSL);
currentDSL.version = 63;
}
if (currentDSL.version === 63) {
currentDSL = migrateMapChartWidgetReskinningData(currentDSL);
currentDSL.version = 64;
}
if (currentDSL.version === 64) {
currentDSL = migrateRateWidgetDisabledState(currentDSL);
currentDSL.version = 65;
}
if (currentDSL.version === 65) {
currentDSL = migrateCodeScannerLayout(currentDSL);
currentDSL.version = 66;
}
if (currentDSL.version === 66) {
currentDSL = migrateTableWidgetV2ValidationBinding(currentDSL);
currentDSL.version = 67;
}
if (currentDSL.version === 67) {
currentDSL = migrateLabelPosition(currentDSL);
currentDSL.version = 68;
}
if (currentDSL.version === 68) {
currentDSL = migratePropertiesForDynamicHeight(currentDSL);
currentDSL.version = 69;
}
if (currentDSL.version === 69) {
currentDSL = migrateMenuButtonDynamicItems(currentDSL);
currentDSL.version = 70;
}
if (currentDSL.version === 70) {
currentDSL = migrateChildStylesheetFromDynamicBindingPathList(currentDSL);
currentDSL.version = 71;
}
if (currentDSL.version === 71) {
currentDSL = migrateTableWidgetV2SelectOption(currentDSL);
currentDSL.version = 72;
}
if (currentDSL.version === 72) {
currentDSL = migrateListWidgetChildrenForAutoHeight(currentDSL);
currentDSL.version = 73;
}
if (currentDSL.version === 73) {
currentDSL = migrateInputWidgetShowStepArrows(currentDSL);
currentDSL.version = 74;
}
if (currentDSL.version === 74) {
currentDSL = migrateMenuButtonDynamicItemsInsideTableWidget(currentDSL);
currentDSL.version = 75;
}
if (currentDSL.version === 75) {
currentDSL = migrateInputWidgetsMultiLineInputType(currentDSL);
currentDSL.version = 76;
}
if (currentDSL.version === 76) {
currentDSL = migrateColumnFreezeAttributes(currentDSL);
currentDSL.version = 77;
}
if (currentDSL.version === 77) {
currentDSL = migrateTableSelectOptionAttributesForNewRow(currentDSL);
currentDSL.version = 78;
}
if (currentDSL.version == 78) {
currentDSL =
migrateBindingPrefixSuffixForInlineEditValidationControl(currentDSL);
currentDSL.version = 79;
}
if (currentDSL.version == 79) {
currentDSL = migrateTableWidgetTableDataJsMode(currentDSL);
currentDSL.version = 80;
}
if (currentDSL.version === 80) {
currentDSL = migrateSelectWidgetOptionToSourceData(currentDSL);
currentDSL.version = 81;
}
if (currentDSL.version === 81) {
currentDSL = migrateSelectWidgetSourceDataBindingPathList(currentDSL);
currentDSL.version = 82;
}
if (currentDSL.version == 82) {
currentDSL = migrateChartWidgetLabelOrientationStaggerOption(currentDSL);
currentDSL.version = 83;
}
if (currentDSL.version == 83) {
currentDSL = migrateAddShowHideDataPointLabels(currentDSL);
currentDSL.version = 84;
}
if (currentDSL.version === 84) {
currentDSL = migrateSelectWidgetAddSourceDataPropertyPathList(currentDSL);
currentDSL.version = 85;
}
if (currentDSL.version === 85) {
currentDSL = migrateDefaultValuesForCustomEChart(currentDSL);
currentDSL.version = 86;
}
if (currentDSL.version === 86) {
currentDSL = migrateTableServerSideFiltering(currentDSL);
currentDSL.version = LATEST_DSL_VERSION;
}
return currentDSL;
};
export const migrateDSL = (
currentDSL: DSLWidget,
newPage = false,
): DSLWidget => {
if (currentDSL.version === undefined) {
const initialDSL = migrateUnversionedDSL(currentDSL);
return migrateVersionedDSL(initialDSL, newPage) as DSLWidget;
} else {
return migrateVersionedDSL(currentDSL, newPage) as DSLWidget;
}
};

View File

@ -0,0 +1,40 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { DSLWidget } from "../types";
import { generateReactKey } from "../utils";
export const updateContainers = (dsl: DSLWidget) => {
if (dsl.type === "CONTAINER_WIDGET" || dsl.type === "FORM_WIDGET") {
if (
!(
dsl.children &&
dsl.children.length > 0 &&
(dsl.children[0].type === "CANVAS_WIDGET" ||
dsl.children[0].type === "FORM_WIDGET")
)
) {
const canvas: any = {
...dsl,
backgroundColor: "transparent",
type: "CANVAS_WIDGET",
detachFromLayout: true,
topRow: 0,
leftColumn: 0,
rightColumn: dsl.parentColumnSpace * (dsl.rightColumn - dsl.leftColumn),
bottomRow: dsl.parentRowSpace * (dsl.bottomRow - dsl.topRow),
widgetName: generateReactKey(),
widgetId: generateReactKey(),
parentRowSpace: 1,
parentColumnSpace: 1,
containerStyle: "none",
canExtend: false,
isVisible: true,
};
delete canvas.dynamicBindings;
delete canvas.dynamicProperties;
if (canvas.children && canvas.children.length > 0)
canvas.children = canvas.children.map(updateContainers);
dsl.children = [{ ...canvas }];
}
}
return dsl;
};

View File

@ -0,0 +1,23 @@
import type { DSLWidget } from "../types";
export const chartDataMigration = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((children: DSLWidget) => {
if (
children.type === "CHART_WIDGET" &&
children.chartData &&
children.chartData.length &&
!Array.isArray(children.chartData[0])
) {
children.chartData = [{ data: children.chartData }];
} else if (
children.type === "CONTAINER_WIDGET" ||
children.type === "FORM_WIDGET" ||
children.type === "CANVAS_WIDGET" ||
children.type === "TABS_WIDGET"
) {
children = chartDataMigration(children);
}
return children;
});
return currentDSL;
};

View File

@ -0,0 +1,62 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { DSLWidget } from "../types";
export const mapDataMigration = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((children: DSLWidget) => {
if (children.type === "MAP_WIDGET") {
if (children.markers) {
children.markers = children.markers.map(
(marker: { lat: any; lng: any; long: any; title: any }) => {
return {
lat: marker.lat,
long: marker.lng || marker.long,
title: marker.title,
};
},
);
}
if (children.defaultMarkers) {
const defaultMarkers = JSON.parse(children.defaultMarkers);
children.defaultMarkers = defaultMarkers.map(
(marker: {
lat: number;
lng: number;
long: number;
title: string;
}) => {
return {
lat: marker.lat,
long: marker.lng || marker.long,
title: marker.title,
};
},
);
}
if (children.selectedMarker) {
children.selectedMarker = {
lat: children.selectedMarker.lat,
long: children.selectedMarker.lng || children.selectedMarker.long,
title: children.selectedMarker.title,
};
}
if (children.mapCenter) {
children.mapCenter = {
lat: children.mapCenter.lat,
long: children.mapCenter.lng || children.mapCenter.long,
title: children.mapCenter.title,
};
}
if (children.center) {
children.center = {
lat: children.center.lat,
long: children.center.lng || children.center.long,
title: children.center.title,
};
}
} else if (children.children && children.children.length > 0) {
children = mapDataMigration(children);
}
return children;
});
return currentDSL;
};

View File

@ -0,0 +1,30 @@
import type { DSLWidget } from "../types";
export const singleChartDataMigration = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "CHART_WIDGET") {
// Check if chart widget has the deprecated singleChartData property
if (child.hasOwnProperty("singleChartData")) {
// This is to make sure that the format of the chartData is accurate
if (
Array.isArray(child.singleChartData) &&
!child.singleChartData[0].hasOwnProperty("seriesName")
) {
child.singleChartData = {
seriesName: "Series 1",
data: child.singleChartData || [],
};
}
//TODO: other possibilities?
child.chartData = JSON.stringify([...child.singleChartData]);
delete child.singleChartData;
}
}
if (child.children && child.children.length > 0) {
child = singleChartDataMigration(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import isString from "lodash/isString";
import log from "loglevel";
import type { DSLWidget } from "../types";
export const tabsWidgetTabsPropertyMigration = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children
?.filter(Boolean)
.map((child: DSLWidget) => {
if (child.type === "TABS_WIDGET") {
try {
const tabs = isString(child.tabs)
? JSON.parse(child.tabs)
: child.tabs;
const newTabs = tabs.map((tab: any) => {
const childForTab = child.children
?.filter(Boolean)
.find((tabChild: DSLWidget) => tabChild.tabId === tab.id);
if (childForTab) {
tab.widgetId = childForTab.widgetId;
}
return tab;
});
child.tabs = JSON.stringify(newTabs);
} catch (migrationError) {
log.debug({ migrationError });
}
}
if (child.children && child.children.length) {
child = tabsWidgetTabsPropertyMigration(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,26 @@
import type { DSLWidget } from "../types";
export const dynamicPathListMigration = (currentDSL: DSLWidget) => {
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map(dynamicPathListMigration);
}
if (currentDSL.dynamicBindings) {
currentDSL.dynamicBindingPathList = Object.keys(
currentDSL.dynamicBindings,
).map((path) => ({ key: path }));
delete currentDSL.dynamicBindings;
}
if (currentDSL.dynamicTriggers) {
currentDSL.dynamicTriggerPathList = Object.keys(
currentDSL.dynamicTriggers,
).map((path) => ({ key: path }));
delete currentDSL.dynamicTriggers;
}
if (currentDSL.dynamicProperties) {
currentDSL.dynamicPropertyPathList = Object.keys(
currentDSL.dynamicProperties,
).map((path) => ({ key: path }));
delete currentDSL.dynamicProperties;
}
return currentDSL;
};

View File

@ -0,0 +1,23 @@
import type { DSLWidget } from "../types";
export const canvasNameConflictMigration = (
currentDSL: DSLWidget,
props = { counter: 1 },
): DSLWidget => {
if (
currentDSL.type === "CANVAS_WIDGET" &&
currentDSL.widgetName.startsWith("Canvas")
) {
currentDSL.widgetName = `Canvas${props.counter}`;
// Canvases inside tabs have `name` property as well
if (currentDSL.name) {
currentDSL.name = currentDSL.widgetName;
}
props.counter++;
}
currentDSL.children?.forEach((c: DSLWidget) =>
canvasNameConflictMigration(c, props),
);
return currentDSL;
};

View File

@ -0,0 +1,25 @@
import { canvasNameConflictMigration } from "./007-canvas-name-conflict-migration";
import type { DSLWidget } from "../types";
export const renamedCanvasNameConflictMigration = (
currentDSL: DSLWidget,
props = { counter: 1 },
): DSLWidget => {
// Rename all canvas widgets except for MainContainer
if (
currentDSL.type === "CANVAS_WIDGET" &&
currentDSL.widgetName !== "MainContainer"
) {
currentDSL.widgetName = `Canvas${props.counter}`;
// Canvases inside tabs have `name` property as well
if (currentDSL.name) {
currentDSL.name = currentDSL.widgetName;
}
props.counter++;
}
currentDSL.children?.forEach((c: DSLWidget) =>
canvasNameConflictMigration(c, props),
);
return currentDSL;
};

View File

@ -0,0 +1,175 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import cloneDeep from "lodash/cloneDeep";
import isString from "lodash/isString";
import type { DSLWidget } from "../types";
import { removeSpecialChars } from "../utils";
export const getAllTableColumnKeys = (
tableData?: Array<Record<string, unknown>>,
) => {
const columnKeys: string[] = [];
if (tableData) {
for (let i = 0, tableRowCount = tableData.length; i < tableRowCount; i++) {
const row = tableData[i];
for (const key in row) {
// Replace all special characters to _, limit key length to 200 characters.
const sanitizedKey = removeSpecialChars(key, 200);
if (!columnKeys.includes(sanitizedKey)) {
columnKeys.push(sanitizedKey);
}
}
}
}
return columnKeys;
};
export const tableWidgetPropertyPaneMigrations = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((_child: DSLWidget) => {
let child = cloneDeep(_child);
// If the current child is a TABLE_WIDGET
if (child.type === "TABLE_WIDGET") {
const hiddenColumns = child.hiddenColumns || [];
const columnNameMap = child.columnNameMap;
const columnSizeMap = child.columnSizeMap;
const columnTypeMap = child.columnTypeMap;
let tableColumns: string[] = [];
const dynamicBindingPathList = child.dynamicBindingPathList;
if (child.tableData.length) {
let tableData = [];
// Try parsing the table data, if it parses great
// If it does not parse, assign tableData the value as is.
try {
tableData = JSON.parse(child.tableData);
} catch (e) {
tableData = child.tableData;
}
if (
!isString(tableData) &&
dynamicBindingPathList?.findIndex(
(item: { key: string }) => item.key !== "tableData",
)
) {
// Get the list of column ids
tableColumns = getAllTableColumnKeys(tableData);
} else {
child.migrated = false;
}
}
// Get primaryColumns to be the list of column keys
// Use the old order if it exists, else use the new order
const primaryColumns = child.columnOrder?.length
? child.columnOrder
: tableColumns;
child.primaryColumns = {};
// const hasActions = child.columnActions && child.columnActions.length > 0;
// Generate new primarycolumns
primaryColumns.forEach((accessor: string, index: number) => {
// Get the column type from the columnTypeMap
let columnType =
columnTypeMap && columnTypeMap[accessor]
? columnTypeMap[accessor].type
: "text";
// If the columnType is currency make it a text type
// We're deprecating currency types
if (columnType === "currency") {
columnType = "text";
}
// Get a full set of column properties
const column: any = {
index, // Use to maintain order of columns
// The widget of the column
width:
columnSizeMap && columnSizeMap[accessor]
? columnSizeMap[accessor]
: 150,
// id of the column
id: accessor,
// default horizontal alignment
horizontalAlignment: "LEFT",
// default vertical alignment
verticalAlignment: "CENTER",
// columnType
columnType,
// default text color
textColor: "#231F20",
// default text size
textSize: "PARAGRAPH",
// default font size
fontStyle: "REGULAR",
enableFilter: true,
enableSort: true,
// hide the column if it was hidden earlier using hiddenColumns
isVisible: hiddenColumns.includes(accessor) ? false : true,
// We did not have a concept of derived columns so far
isDerived: false,
// Use renamed names from the map
// or use the newly generated name
label:
columnNameMap && columnNameMap[accessor]
? columnNameMap[accessor]
: accessor,
// Generate computed value
computedValue: `{{${child.widgetName}.sanitizedTableData.map((currentRow) => ( currentRow.${accessor})}}`,
};
// copy inputForma nd outputFormat for date column types
if (columnTypeMap && columnTypeMap[accessor]) {
column.outputFormat = columnTypeMap[accessor].format || "";
column.inputFormat = columnTypeMap[accessor].inputFormat || "";
}
child.primaryColumns[column.id] = column;
});
// Get all column actions
const columnActions = child.columnActions || [];
// Get dynamicTriggerPathList
let dynamicTriggerPathList: Array<{ key: string }> =
child.dynamicTriggerPathList || [];
const columnPrefix = "customColumn";
const updatedDerivedColumns: Record<string, object> = {};
// Add derived column for each column action
columnActions.forEach((action: any, index: number) => {
const column = {
index: child.primaryColumns.length + index, // Add to the end of the columns list
width: 150, // Default width
id: `${columnPrefix}${index + 1}`, // A random string which was generated previously
label: action.label, // Revert back to "Actions"
columnType: "button", // All actions are buttons
isVisible: true,
isDisabled: false,
isDerived: true,
buttonLabel: action.label,
buttonStyle: "rgb(3, 179, 101)",
buttonLabelColor: "#FFFFFF",
onClick: action.dynamicTrigger,
computedValue: "",
};
dynamicTriggerPathList.push({
key: `primaryColumns.${columnPrefix}${index + 1}.onClick`,
});
updatedDerivedColumns[column.id] = column;
child.primaryColumns[column.id] = column;
});
if (Object.keys(updatedDerivedColumns).length) {
dynamicTriggerPathList = dynamicTriggerPathList.filter(
(triggerPath: Record<string, string>) => {
triggerPath.key !== "columnActions";
},
);
}
child.dynamicTriggerPathList = dynamicTriggerPathList;
child.textSize = "PARAGRAPH";
child.horizontalAlignment = "LEFT";
child.verticalAlignment = "CENTER";
child.fontStyle = "REGULAR";
child.derivedColumns = updatedDerivedColumns;
} else if (child.children && child.children.length > 0) {
child = tableWidgetPropertyPaneMigrations(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,11 @@
import type { DSLWidget } from "../types";
export const addVersionNumberMigration = (currentDSL: DSLWidget) => {
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map(addVersionNumberMigration);
}
if (currentDSL.version === undefined) {
currentDSL.version = 1;
}
return currentDSL;
};

View File

@ -0,0 +1,42 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { DSLWidget } from "../types";
import { removeSpecialChars } from "../utils";
export const migrateTablePrimaryColumnsBindings = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
if (
child.primaryColumns &&
Object.keys(child.primaryColumns).length > 0
) {
const newPrimaryColumns: Record<string, any> = {};
for (const [key, value] of Object.entries(
child.primaryColumns as Record<string, any>,
)) {
const sanitizedKey = removeSpecialChars(key, 200);
const newComputedValue = value.computedValue
? value.computedValue.replace(
`${child.widgetName}.tableData.map`,
`${child.widgetName}.sanitizedTableData.map`,
)
: "";
newPrimaryColumns[sanitizedKey] = {
...value,
computedValue: newComputedValue,
};
}
child.primaryColumns = newPrimaryColumns;
child.dynamicBindingPathList = child.dynamicBindingPathList?.map(
(path: { key: string }) => {
path.key = path.key.split(" ").join("_");
return path;
},
);
}
} else if (child.children && child.children.length > 0) {
child = migrateTablePrimaryColumnsBindings(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,934 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import flow from "lodash/flow";
import type { DSLWidget } from "../types";
import log from "loglevel";
import get from "lodash/get";
import isString from "lodash/isString";
import memoize from "micro-memoize";
import { isObject, isUndefined } from "lodash";
import { generateReactKey, isDynamicValue } from "../utils";
import widgetConfigs from "../helpers/widget-configs.json";
export const WidgetHeightLimits = {
MAX_HEIGHT_IN_ROWS: 9000,
MIN_HEIGHT_IN_ROWS: 4,
MIN_CANVAS_HEIGHT_IN_ROWS: 10,
};
function updateMinMaxDynamicHeight(
props: any,
propertyName: string,
propertyValue: unknown,
) {
const updates = [
{
propertyPath: propertyName,
propertyValue: propertyValue,
},
];
if (propertyValue === "AUTO_HEIGHT_WITH_LIMITS") {
const minDynamicHeight = parseInt(props.minDynamicHeight, 10);
if (
isNaN(minDynamicHeight) ||
minDynamicHeight < WidgetHeightLimits.MIN_HEIGHT_IN_ROWS
) {
updates.push({
propertyPath: "minDynamicHeight",
propertyValue: WidgetHeightLimits.MIN_HEIGHT_IN_ROWS,
});
}
const maxDynamicHeight = parseInt(props.maxDynamicHeight, 10);
if (
isNaN(maxDynamicHeight) ||
maxDynamicHeight === WidgetHeightLimits.MAX_HEIGHT_IN_ROWS ||
maxDynamicHeight <= WidgetHeightLimits.MIN_HEIGHT_IN_ROWS
) {
updates.push({
propertyPath: "maxDynamicHeight",
propertyValue: props.bottomRow - props.topRow + 2,
});
}
// Case where maxDynamicHeight is zero
if (isNaN(maxDynamicHeight) || maxDynamicHeight === 0) {
updates.push({
propertyPath: "maxDynamicHeight",
propertyValue: props.bottomRow - props.topRow,
});
}
} else if (propertyValue === "AUTO_HEIGHT") {
const minHeightInRows = props.isCanvas
? WidgetHeightLimits.MIN_CANVAS_HEIGHT_IN_ROWS
: WidgetHeightLimits.MIN_HEIGHT_IN_ROWS;
updates.push(
{
propertyPath: "minDynamicHeight",
propertyValue: minHeightInRows,
},
{
propertyPath: "maxDynamicHeight",
propertyValue: WidgetHeightLimits.MAX_HEIGHT_IN_ROWS,
},
);
}
if (propertyValue === "FIXED") {
updates.push({
propertyPath: "originalBottomRow",
propertyValue: undefined,
});
updates.push({
propertyPath: "originalTopRow",
propertyValue: undefined,
});
}
// The following are updates which apply to specific widgets.
if (
propertyValue === "AUTO_HEIGHT" ||
propertyValue === "AUTO_HEIGHT_WITH_LIMITS"
) {
if (props.dynamicHeight === "FIXED") {
updates.push({
propertyPath: "originalBottomRow",
propertyValue: props.bottomRow,
});
updates.push({
propertyPath: "originalTopRow",
propertyValue: props.topRow,
});
}
if (!props.shouldScrollContents) {
updates.push({
propertyPath: "shouldScrollContents",
propertyValue: true,
});
}
if (props.overflow !== undefined) {
updates.push({
propertyPath: "overflow",
propertyValue: "NONE",
});
}
if (props.scrollContents === true) {
updates.push({
propertyPath: "scrollContents",
propertyValue: false,
});
}
if (props.fixedFooter === true) {
updates.push({
propertyPath: "fixedFooter",
propertyValue: false,
});
}
}
return updates;
}
export const PropertyPaneConfigTemplates: Record<string, any[]> = {
dynamicHeight: [
{
helpText:
"Auto Height: Configure the way the widget height reacts to content changes.",
propertyName: "dynamicHeight",
label: "Height",
controlType: "DROP_DOWN",
isBindProperty: false,
isTriggerProperty: false,
dependencies: [
"shouldScrollContents",
"maxDynamicHeight",
"minDynamicHeight",
"bottomRow",
"topRow",
"overflow",
"dynamicHeight",
"isCanvas",
],
updateHook: updateMinMaxDynamicHeight,
helperText: (props: any) => {
return props.isCanvas && props.dynamicHeight === "AUTO_HEIGHT"
? "This widget shows an internal scroll when you add widgets in edit mode. It'll resize after you've added widgets. The scroll won't exist in view mode."
: "";
},
options: [
{
label: "Auto Height",
value: "AUTO_HEIGHT",
},
{
label: "Auto Height with limits",
value: "AUTO_HEIGHT_WITH_LIMITS",
},
{
label: "Fixed",
value: "FIXED",
},
],
postUpdateAction: "CHECK_CONTAINERS_FOR_AUTO_HEIGHT",
},
],
};
function findAndUpdatePropertyPaneControlConfig(
config: any[],
propertyPaneUpdates: Record<string, Record<string, unknown>>,
): any[] {
return config.map((sectionConfig: any) => {
if (
Array.isArray(sectionConfig.children) &&
sectionConfig.children.length > 0
) {
Object.keys(propertyPaneUpdates).forEach((propertyName: string) => {
const controlConfigIndex: number | undefined =
sectionConfig.children?.findIndex(
(controlConfig: any) => controlConfig.propertyName === propertyName,
);
if (
controlConfigIndex !== undefined &&
controlConfigIndex > -1 &&
sectionConfig.children
) {
sectionConfig.children[controlConfigIndex] = {
...sectionConfig.children[controlConfigIndex],
...propertyPaneUpdates[propertyName],
};
}
});
}
return sectionConfig;
});
}
const WidgetFeaturePropertyPaneEnhancements: Record<
string,
(config: any[], widgetType?: string) => any[]
> = {
dynamicHeight: (config: any[], widgetType?: string) => {
function hideWhenDynamicHeightIsEnabled(props: any) {
return (
props.dynamicHeight === "AUTO_HEIGHT_WITH_LIMITS" ||
props.dynamicHeight === "AUTO_HEIGHT"
);
}
let update = findAndUpdatePropertyPaneControlConfig(config, {
shouldScrollContents: {
hidden: hideWhenDynamicHeightIsEnabled,
dependencies: ["dynamicHeight"],
},
scrollContents: {
hidden: hideWhenDynamicHeightIsEnabled,
dependencies: ["dynamicHeight"],
},
fixedFooter: {
hidden: hideWhenDynamicHeightIsEnabled,
dependencies: ["dynamicHeight"],
},
overflow: {
hidden: hideWhenDynamicHeightIsEnabled,
dependencies: ["dynamicHeight"],
},
});
if (widgetType === "MODAL_WIDGET") {
update = findAndUpdatePropertyPaneControlConfig(update, {
dynamicHeight: {
options: [
{
label: "Auto Height",
value: "AUTO_HEIGHT",
},
{
label: "Fixed",
value: "FIXED",
},
],
},
});
}
return update;
},
};
function enhancePropertyPaneConfig(
config: any[],
features?: any,
configType?: string,
widgetType?: string,
) {
// Enhance property pane with widget features
// TODO(abhinav): The following "configType" check should come
// from the features themselves.
if (features && (configType === undefined || configType === "CONTENT")) {
Object.keys(features).forEach((registeredFeature: string) => {
const { sectionIndex } = features[registeredFeature];
const sectionName = config[sectionIndex]?.sectionName;
// This has been designed to check if the sectionIndex provided in the
// features configuration of the widget to point to the section named "General"
// If not, it logs an error
// This is a sanity check, and doesn't effect the functionality of the feature
// For consistency, we expect that all "Auto Height" property pane controls
// be present in the "General" section of the property pane
if (!sectionName || sectionName !== "General") {
log.error(
`Invalid section index for feature: ${registeredFeature} in widget: ${widgetType}`,
);
}
if (
Array.isArray(config[sectionIndex].children) &&
PropertyPaneConfigTemplates[registeredFeature]
) {
config[sectionIndex].children?.push(
...PropertyPaneConfigTemplates[registeredFeature],
);
config = WidgetFeaturePropertyPaneEnhancements[registeredFeature](
config,
widgetType,
);
}
});
}
return config;
}
export function convertFunctionsToString(config: any[]) {
return config.map((sectionOrControlConfig: any) => {
const controlConfig = sectionOrControlConfig;
if (
controlConfig.validation &&
controlConfig.validation?.type === "FUNCTION" &&
controlConfig.validation?.params &&
controlConfig.validation?.params.fn
) {
controlConfig.validation.params.fnString =
controlConfig.validation.params.fn.toString();
delete controlConfig.validation.params.fn;
return sectionOrControlConfig;
}
if (sectionOrControlConfig.children) {
sectionOrControlConfig.children = convertFunctionsToString(
sectionOrControlConfig.children,
);
}
const config = sectionOrControlConfig;
if (
config.panelConfig &&
config.panelConfig.children &&
Array.isArray(config.panelConfig.children)
) {
config.panelConfig.children = convertFunctionsToString(
config.panelConfig.children,
);
sectionOrControlConfig = config;
}
if (
config.panelConfig &&
config.panelConfig.contentChildren &&
Array.isArray(config.panelConfig.contentChildren)
) {
config.panelConfig.contentChildren = convertFunctionsToString(
config.panelConfig.contentChildren,
);
sectionOrControlConfig = config;
}
if (
config.panelConfig &&
config.panelConfig.styleChildren &&
Array.isArray(config.panelConfig.styleChildren)
) {
config.panelConfig.styleChildren = convertFunctionsToString(
config.panelConfig.styleChildren,
);
sectionOrControlConfig = config;
}
return sectionOrControlConfig;
});
}
export const addPropertyConfigIds = (config: any[]) => {
return config.map((sectionOrControlConfig: any) => {
sectionOrControlConfig.id = generateReactKey();
if (sectionOrControlConfig.children) {
sectionOrControlConfig.children = addPropertyConfigIds(
sectionOrControlConfig.children,
);
}
const config = sectionOrControlConfig;
if (config.panelConfig) {
if (
config.panelConfig.children &&
Array.isArray(config.panelConfig.children)
) {
config.panelConfig.children = addPropertyConfigIds(
config.panelConfig.children,
);
}
if (
config.panelConfig.contentChildren &&
Array.isArray(config.panelConfig.contentChildren)
) {
config.panelConfig.contentChildren = addPropertyConfigIds(
config.panelConfig.contentChildren,
);
}
if (
config.panelConfig.styleChildren &&
Array.isArray(config.panelConfig.styleChildren)
) {
config.panelConfig.styleChildren = addPropertyConfigIds(
config.panelConfig.styleChildren,
);
}
sectionOrControlConfig = config;
}
return sectionOrControlConfig;
});
};
function addSearchSpecificPropertiesToConfig(
config: readonly any[],
tag: string,
): any[] {
return config.map((configItem) => {
if (configItem.sectionName) {
const sectionConfig = {
...configItem,
collapsible: false,
tag,
};
if (configItem.children) {
sectionConfig.children = addSearchSpecificPropertiesToConfig(
configItem.children,
tag,
);
}
return sectionConfig;
} else if (configItem.controlType) {
const controlConfig = configItem;
if (controlConfig.panelConfig) {
return {
...controlConfig,
panelConfig: {
...controlConfig.panelConfig,
searchConfig: generatePropertyPaneSearchConfig(
controlConfig.panelConfig?.contentChildren ?? [],
controlConfig.panelConfig?.styleChildren ?? [],
),
},
};
}
return controlConfig;
}
return configItem;
});
}
export function generatePropertyPaneSearchConfig(
contentConfig: readonly any[],
styleConfig: readonly any[],
) {
return [
...addSearchSpecificPropertiesToConfig(contentConfig, "CONTENT"),
...addSearchSpecificPropertiesToConfig(styleConfig, "STYLE"),
];
}
export function addSearchConfigToPanelConfig(config: readonly any[]) {
return config.map((configItem) => {
if (configItem.sectionName) {
const sectionConfig = {
...configItem,
};
if (configItem.children) {
sectionConfig.children = addSearchConfigToPanelConfig(
configItem.children,
);
}
return sectionConfig;
} else if (configItem.controlType) {
const controlConfig = configItem;
if (controlConfig.panelConfig) {
return {
...controlConfig,
panelConfig: {
...controlConfig.panelConfig,
searchConfig: generatePropertyPaneSearchConfig(
controlConfig.panelConfig?.contentChildren ?? [],
controlConfig.panelConfig?.styleChildren ?? [],
),
},
};
}
return controlConfig;
}
return configItem;
});
}
const getWidgetPropertyPaneContentConfig = (type: string): readonly any[] => {
const propertyPaneContentConfig = (widgetConfigs as any)[type]
.propertyPaneContentConfig;
const features = (widgetConfigs as any)[type].features;
if (propertyPaneContentConfig) {
const enhance = flow([
enhancePropertyPaneConfig,
convertFunctionsToString,
addPropertyConfigIds,
addSearchConfigToPanelConfig,
Object.freeze,
]);
const enhancedPropertyPaneContentConfig = enhance(
propertyPaneContentConfig,
features,
"CONTENT",
type,
);
return enhancedPropertyPaneContentConfig;
} else {
return [];
}
};
const getWidgetPropertyPaneStyleConfig = (type: string): readonly any[] => {
const propertyPaneStyleConfig = (widgetConfigs as any)[type]
.propertyPaneStyleConfig;
const features = (widgetConfigs as any)[type].features;
if (propertyPaneStyleConfig) {
const enhance = flow([
enhancePropertyPaneConfig,
convertFunctionsToString,
addPropertyConfigIds,
addSearchConfigToPanelConfig,
Object.freeze,
]);
const enhancedPropertyPaneConfig = enhance(
propertyPaneStyleConfig,
features,
"STYLE",
);
return enhancedPropertyPaneConfig;
} else {
return [];
}
};
const getWidgetPropertyPaneCombinedConfig = (type: string): readonly any[] => {
const contentConfig = getWidgetPropertyPaneContentConfig(type);
const styleConfig = getWidgetPropertyPaneStyleConfig(type);
return [...contentConfig, ...styleConfig];
};
const getWidgetPropertyPaneConfig = (type: string): readonly any[] => {
const propertyPaneConfig = (widgetConfigs as any)[type].propertyPaneConfig;
const features = (widgetConfigs as any)[type].features;
if (Array.isArray(propertyPaneConfig) && propertyPaneConfig.length > 0) {
const enhance = flow([
enhancePropertyPaneConfig,
convertFunctionsToString,
addPropertyConfigIds,
Object.freeze,
]);
const enhancedPropertyPaneConfig = enhance(propertyPaneConfig, features);
return enhancedPropertyPaneConfig;
} else {
const config = getWidgetPropertyPaneCombinedConfig(type);
if (config === undefined) {
log.error("Widget property pane config not defined", type);
return [];
} else {
return config;
}
}
};
const checkPathsInConfig = (
config: any,
path: string,
): {
configBindingPaths: any;
configReactivePaths: any;
configTriggerPaths: Record<string, true>;
configValidationPaths: Record<string, any>;
} => {
const configBindingPaths: any = {};
const configTriggerPaths: Record<string, true> = {};
const configValidationPaths: Record<any, any> = {};
// Purely a Binding Path
if (config.isBindProperty && !config.isTriggerProperty) {
configBindingPaths[path] = config.evaluationSubstitutionType || "TEMPLATE";
if (config.validation) {
configValidationPaths[path] = config.validation;
}
} else if (config.isBindProperty && config.isTriggerProperty) {
configTriggerPaths[path] = true;
}
return {
configBindingPaths,
configReactivePaths: configBindingPaths, // All bindingPaths are reactivePaths.
configTriggerPaths,
configValidationPaths,
};
};
const childHasPanelConfig = (
config: any,
widget: any,
basePath: string,
originalWidget: any,
) => {
const panelPropertyPath = config.propertyName;
const widgetPanelPropertyValues = get(widget, panelPropertyPath);
let bindingPaths: any = {};
let reactivePaths: any = {};
let triggerPaths: Record<string, true> = {};
let validationPaths: Record<any, any> = {};
if (widgetPanelPropertyValues) {
Object.values(widgetPanelPropertyValues).forEach(
(widgetPanelPropertyValue: any) => {
const { panelIdPropertyName } = config.panelConfig;
const propertyPath = `${basePath}.${widgetPanelPropertyValue[panelIdPropertyName]}`;
let panelConfigChildren = [
...(config.panelConfig.contentChildren || []),
...(config.panelConfig.styleChildren || []),
];
if (panelConfigChildren.length === 0)
panelConfigChildren = config.panelConfig.children;
panelConfigChildren.forEach((panelColumnConfig: any) => {
let isSectionHidden = false;
if ("hidden" in panelColumnConfig) {
isSectionHidden = panelColumnConfig.hidden(
originalWidget,
propertyPath,
);
}
if (!isSectionHidden) {
panelColumnConfig.children.forEach(
(panelColumnControlOrSectionConfig: any) => {
if (
panelColumnControlOrSectionConfig.sectionName !== undefined
) {
panelColumnControlOrSectionConfig.children.forEach(
(panelColumnControlConfig: any) => {
const panelPropertyConfigPath = `${propertyPath}.${panelColumnControlConfig.propertyName}`;
let isControlHidden = false;
if ("hidden" in panelColumnControlConfig) {
isControlHidden = panelColumnControlConfig.hidden(
originalWidget,
panelPropertyConfigPath,
);
}
if (!isControlHidden) {
const {
configBindingPaths,
configReactivePaths,
configTriggerPaths,
configValidationPaths,
} = checkPathsInConfig(
panelColumnControlConfig,
panelPropertyConfigPath,
);
bindingPaths = {
...configBindingPaths,
...bindingPaths,
};
reactivePaths = {
...configReactivePaths,
...reactivePaths,
};
triggerPaths = {
...configTriggerPaths,
...triggerPaths,
};
validationPaths = {
...configValidationPaths,
...validationPaths,
};
// Has child Panel Config
if (panelColumnControlConfig.panelConfig) {
const {
bindingPaths: panelBindingPaths,
reactivePaths: panelReactivePaths,
triggerPaths: panelTriggerPaths,
validationPaths: panelValidationPaths,
} = childHasPanelConfig(
panelColumnControlConfig,
widgetPanelPropertyValue,
panelPropertyConfigPath,
originalWidget,
);
bindingPaths = {
...panelBindingPaths,
...bindingPaths,
};
reactivePaths = {
...panelReactivePaths,
...reactivePaths,
};
triggerPaths = {
...panelTriggerPaths,
...triggerPaths,
};
validationPaths = {
...panelValidationPaths,
...validationPaths,
};
}
}
},
);
} else {
const panelPropertyConfigPath = `${propertyPath}.${panelColumnControlOrSectionConfig.propertyName}`;
let isControlHidden = false;
if ("hidden" in panelColumnControlOrSectionConfig) {
isControlHidden = panelColumnControlOrSectionConfig.hidden(
originalWidget,
panelPropertyConfigPath,
);
}
if (!isControlHidden) {
const {
configBindingPaths,
configReactivePaths,
configTriggerPaths,
configValidationPaths,
} = checkPathsInConfig(
panelColumnControlOrSectionConfig,
panelPropertyConfigPath,
);
bindingPaths = {
...configBindingPaths,
...bindingPaths,
};
reactivePaths = {
...configReactivePaths,
...reactivePaths,
};
triggerPaths = { ...configTriggerPaths, ...triggerPaths };
validationPaths = {
...configValidationPaths,
...validationPaths,
};
// Has child Panel Config
if (panelColumnControlOrSectionConfig.panelConfig) {
const {
bindingPaths: panelBindingPaths,
reactivePaths: panelReactivePaths,
triggerPaths: panelTriggerPaths,
validationPaths: panelValidationPaths,
} = childHasPanelConfig(
panelColumnControlOrSectionConfig,
widgetPanelPropertyValue,
panelPropertyConfigPath,
originalWidget,
);
bindingPaths = {
...panelBindingPaths,
...bindingPaths,
};
reactivePaths = {
...panelReactivePaths,
...reactivePaths,
};
triggerPaths = { ...panelTriggerPaths, ...triggerPaths };
validationPaths = {
...panelValidationPaths,
...validationPaths,
};
}
}
}
},
);
}
});
},
);
}
return { reactivePaths, triggerPaths, validationPaths, bindingPaths };
};
const getAllPathsFromPropertyConfigWithoutMemo = (
widget: any,
widgetConfig: readonly any[],
defaultProperties: Record<string, any>,
): {
bindingPaths: any;
reactivePaths: any;
triggerPaths: Record<string, true>;
validationPaths: Record<string, any>;
} => {
let bindingPaths: any = {};
let reactivePaths: any = {};
Object.keys(defaultProperties).forEach((property) => {
reactivePaths[property] = "TEMPLATE";
});
let triggerPaths: Record<string, true> = {};
let validationPaths: Record<any, any> = {};
widgetConfig.forEach((config) => {
if (config.children) {
config.children.forEach((controlConfig: any) => {
const basePath = controlConfig.propertyName;
let isHidden = false;
if ("hidden" in controlConfig) {
isHidden = controlConfig.hidden(widget, basePath);
}
if (!isHidden) {
const path = controlConfig.propertyName;
const {
configBindingPaths,
configReactivePaths,
configTriggerPaths,
configValidationPaths,
} = checkPathsInConfig(controlConfig, path);
bindingPaths = {
...bindingPaths,
...configBindingPaths,
};
// Update default path configs with the ones in the property config
reactivePaths = {
...reactivePaths,
...configReactivePaths,
};
triggerPaths = { ...triggerPaths, ...configTriggerPaths };
validationPaths = { ...validationPaths, ...configValidationPaths };
}
// Has child Panel Config
if (controlConfig.panelConfig) {
const resultingPaths = childHasPanelConfig(
controlConfig,
widget,
basePath,
widget,
);
bindingPaths = {
...bindingPaths,
...resultingPaths.bindingPaths,
};
reactivePaths = {
...reactivePaths,
...resultingPaths.reactivePaths,
};
triggerPaths = { ...triggerPaths, ...resultingPaths.triggerPaths };
validationPaths = {
...validationPaths,
...resultingPaths.validationPaths,
};
}
if (controlConfig.children) {
const basePropertyPath = controlConfig.propertyName;
const widgetPropertyValue = get(widget, basePropertyPath, []);
// Property in object structure
if (
!isUndefined(widgetPropertyValue) &&
isObject(widgetPropertyValue)
) {
Object.keys(widgetPropertyValue).forEach((key: string) => {
const objectIndexPropertyPath = `${basePropertyPath}.${key}`;
controlConfig.children.forEach((childPropertyConfig: any) => {
const childArrayPropertyPath = `${objectIndexPropertyPath}.${childPropertyConfig.propertyName}`;
const {
configBindingPaths,
configReactivePaths,
configTriggerPaths,
configValidationPaths,
} = checkPathsInConfig(
childPropertyConfig,
childArrayPropertyPath,
);
bindingPaths = {
...bindingPaths,
...configBindingPaths,
};
reactivePaths = {
...reactivePaths,
...configReactivePaths,
};
triggerPaths = { ...triggerPaths, ...configTriggerPaths };
validationPaths = {
...validationPaths,
...configValidationPaths,
};
});
});
}
}
});
}
});
return { reactivePaths, triggerPaths, validationPaths, bindingPaths };
};
const getAllPathsFromPropertyConfig = memoize(
getAllPathsFromPropertyConfigWithoutMemo,
{ maxSize: 1000 },
);
export const migrateIncorrectDynamicBindingPathLists = (
currentDSL: Readonly<DSLWidget>,
): DSLWidget => {
const migratedDsl = {
...currentDSL,
};
const dynamicBindingPathList: any[] = [];
const propertyPaneConfig = getWidgetPropertyPaneConfig(currentDSL.type);
const { bindingPaths } = getAllPathsFromPropertyConfig(
currentDSL,
propertyPaneConfig,
{},
);
Object.keys(bindingPaths).forEach((bindingPath) => {
const pathValue = get(migratedDsl, bindingPath);
if (pathValue && isString(pathValue)) {
if (isDynamicValue(pathValue)) {
dynamicBindingPathList.push({ key: bindingPath });
}
}
});
migratedDsl.dynamicBindingPathList = dynamicBindingPathList;
if (currentDSL.children) {
migratedDsl.children = currentDSL.children.map(
migrateIncorrectDynamicBindingPathLists,
);
}
return migratedDsl;
};

View File

@ -0,0 +1,22 @@
import isString from "lodash/isString";
import type { DSLWidget } from "../types";
export const migrateOldChartData = (currentDSL: DSLWidget) => {
if (currentDSL.type === "CHART_WIDGET") {
if (isString(currentDSL.chartData)) {
try {
currentDSL.chartData = JSON.parse(currentDSL.chartData);
} catch (error) {
// Sentry.captureException({
// message: "Chart Migration F`ailed",
// oldData: currentDSL.chartData,
// });
currentDSL.chartData = [];
}
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map(migrateOldChartData);
}
return currentDSL;
};

View File

@ -0,0 +1,12 @@
import type { DSLWidget } from "../types";
export const rteDefaultValueMigration = (currentDSL: DSLWidget): DSLWidget => {
if (currentDSL.type === "RICH_TEXT_EDITOR_WIDGET") {
currentDSL.inputType = "html";
}
currentDSL.children?.forEach((children: DSLWidget) =>
rteDefaultValueMigration(children),
);
return currentDSL;
};

View File

@ -0,0 +1,33 @@
import type { DSLWidget } from "../types";
export const migrateTextStyleFromTextWidget = (
currentDSL: DSLWidget,
): DSLWidget => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TEXT_WIDGET") {
const textStyle = child.textStyle;
switch (textStyle) {
case "HEADING":
child.fontSize = "HEADING1";
child.fontStyle = "BOLD";
break;
case "BODY":
child.fontSize = "PARAGRAPH";
child.fontStyle = "";
break;
case "LABEL":
child.fontSize = "PARAGRAPH";
child.fontStyle = "BOLD";
break;
default:
break;
}
child.textColor = "#231F20";
delete child.textStyle;
} else if (child.children && child.children.length > 0) {
child = migrateTextStyleFromTextWidget(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,60 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { set } from "lodash";
import type { DSLWidget } from "../types";
import { generateReactKey } from "../utils";
/**
* changes chartData which we were using as array. now it will be a object
*
*
* @param currentDSL
* @returns
*/
export const migrateChartDataFromArrayToObject = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((children: DSLWidget) => {
if (children.type === "CHART_WIDGET") {
if (Array.isArray(children.chartData)) {
const newChartData = {};
const dynamicBindingPathList = children?.dynamicBindingPathList
? children?.dynamicBindingPathList.slice()
: [];
children.chartData.map((datum: any, index: number) => {
const generatedKey = generateReactKey();
set(newChartData, `${generatedKey}`, datum);
if (
Array.isArray(children.dynamicBindingPathList) &&
children.dynamicBindingPathList?.findIndex(
(path: { key: string }) =>
(path.key = `chartData[${index}].data`),
) > -1
) {
const foundIndex = children.dynamicBindingPathList.findIndex(
(path: { key: string }) =>
(path.key = `chartData[${index}].data`),
);
dynamicBindingPathList[foundIndex] = {
key: `chartData.${generatedKey}.data`,
};
}
});
children.dynamicBindingPathList = dynamicBindingPathList;
children.chartData = newChartData;
}
} else if (
children.type === "CONTAINER_WIDGET" ||
children.type === "FORM_WIDGET" ||
children.type === "CANVAS_WIDGET" ||
children.type === "TABS_WIDGET"
) {
children = migrateChartDataFromArrayToObject(children);
}
return children;
});
return currentDSL;
};

View File

@ -0,0 +1,103 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { isString } from "lodash";
import type { DSLWidget } from "../types";
import { DATA_BIND_REGEX_GLOBAL } from "../utils";
function migrateTabsDataUsingMigrator(currentDSL: DSLWidget) {
if (currentDSL.type === "TABS_WIDGET" && currentDSL.version === 1) {
try {
currentDSL.type = "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 const migrateTabsData = (currentDSL: DSLWidget) => {
if (
["TABS_WIDGET", "TABS_MIGRATOR_WIDGET"].includes(currentDSL.type) &&
currentDSL.version === 1
) {
try {
currentDSL.type = "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: { key: string }) => {
return each.key !== "tabs";
});
currentDSL.dynamicBindingPathList =
currentDSL.dynamicBindingPathList.filter((each: { key: string }) => {
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;
};

View File

@ -0,0 +1,66 @@
import type { DSLWidget } from "../types";
export const migrateInitialValues = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "INPUT_WIDGET") {
child = {
isRequired: false,
isDisabled: false,
resetOnSubmit: false,
...child,
};
} else if (child.type === "DROP_DOWN_WIDGET") {
child = {
isRequired: false,
isDisabled: false,
...child,
};
} else if (child.type === "DATE_PICKER_WIDGET2") {
child = {
minDate: "2001-01-01 00:00",
maxDate: "2041-12-31 23:59",
isRequired: false,
...child,
};
} else if (child.type === "SWITCH_WIDGET") {
child = {
isDisabled: false,
...child,
};
} else if (child.type === "ICON_WIDGET") {
child = {
isRequired: false,
...child,
};
} else if (child.type === "VIDEO_WIDGET") {
child = {
isRequired: false,
isDisabled: false,
...child,
};
} else if (child.type === "CHECKBOX_WIDGET") {
child = {
isDisabled: false,
isRequired: false,
...child,
};
} else if (child.type === "RADIO_GROUP_WIDGET") {
child = {
isDisabled: false,
isRequired: false,
...child,
};
} else if (child.type === "FILE_PICKER_WIDGET") {
child = {
isDisabled: false,
isRequired: false,
allowedFileTypes: [],
...child,
};
} else if (child.children && child.children.length > 0) {
child = migrateInitialValues(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,35 @@
import type { DSLWidget } from "../types";
const DEFAULT_GRID_ROW_HEIGHT = 10;
const GRID_DENSITY_MIGRATION_V1 = 4;
export const getCanvasSnapRows = (
bottomRow: number,
mobileBottomRow?: number,
isMobile?: boolean,
isAutoLayoutActive?: boolean,
): number => {
const bottom =
isMobile && mobileBottomRow !== undefined && isAutoLayoutActive
? mobileBottomRow
: bottomRow;
const totalRows = Math.floor(bottom / DEFAULT_GRID_ROW_HEIGHT);
return isAutoLayoutActive ? totalRows : totalRows - 1;
};
export const migrateToNewLayout = (dsl: DSLWidget) => {
const scaleWidget = (widgetProps: DSLWidget) => {
widgetProps.bottomRow *= GRID_DENSITY_MIGRATION_V1;
widgetProps.topRow *= GRID_DENSITY_MIGRATION_V1;
widgetProps.leftColumn *= GRID_DENSITY_MIGRATION_V1;
widgetProps.rightColumn *= GRID_DENSITY_MIGRATION_V1;
if (widgetProps.children && widgetProps.children.length) {
widgetProps.children.forEach((eachWidgetProp: DSLWidget) => {
scaleWidget(eachWidgetProp);
});
}
};
scaleWidget(dsl);
return dsl;
};

View File

@ -0,0 +1,41 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import has from "lodash/has";
import type { DSLWidget } from "../types";
export const migrateNewlyAddedTabsWidgetsMissingData = (
currentDSL: DSLWidget,
) => {
if (currentDSL.type === "TABS_WIDGET" && currentDSL.version === 2) {
try {
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((each: any) => {
if (has(currentDSL, ["leftColumn", "rightColumn", "bottomRow"])) {
return each;
}
return {
...each,
leftColumn: 0,
rightColumn:
(currentDSL.rightColumn - currentDSL.leftColumn) *
currentDSL.parentColumnSpace,
bottomRow:
(currentDSL.bottomRow - currentDSL.topRow) *
currentDSL.parentRowSpace,
};
});
}
currentDSL.version = 3;
} catch (error) {
// Sentry.captureException({
// message: "Tabs Migration to add missing fields Failed",
// oldData: currentDSL.children,
// });
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map(
migrateNewlyAddedTabsWidgetsMissingData,
);
}
return currentDSL;
};

View File

@ -0,0 +1,114 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { omit, omitBy } from "lodash";
import type { DSLWidget } from "../types";
const MAIN_CONTAINER_WIDGET_ID = "0";
/**
* this function gets the next available row for pasting widgets
* NOTE: this function excludes modal widget when calculating next available row
*
* @param parentContainerId
* @param canvasWidgets
* @returns
*/
const nextAvailableRowInContainer = (
parentContainerId: string,
canvasWidgets: any,
) => {
const filteredCanvasWidgets = omitBy(canvasWidgets, (widget) => {
return widget.type === "MODAL_WIDGET";
});
return (
Object.values(filteredCanvasWidgets).reduce(
(prev: number, next: any) =>
next?.parentId === parentContainerId && next.bottomRow > prev
? next.bottomRow
: prev,
0,
) + 1
);
};
export const migrateWidgetsWithoutLeftRightColumns = (
currentDSL: DSLWidget,
canvasWidgets: any,
) => {
if (
currentDSL.widgetId !== MAIN_CONTAINER_WIDGET_ID &&
!(
currentDSL.hasOwnProperty("leftColumn") &&
currentDSL.hasOwnProperty("rightColumn")
)
) {
try {
const nextRow = nextAvailableRowInContainer(
currentDSL.parentId || MAIN_CONTAINER_WIDGET_ID,
omit(canvasWidgets, [currentDSL.widgetId]),
);
canvasWidgets[currentDSL.widgetId].repositioned = true;
const leftColumn = 0;
// TODO(abhinav): Figure out a way to get the correct values from the widgets
const rightColumn = 4;
const bottomRow = nextRow + (currentDSL.bottomRow - currentDSL.topRow);
const topRow = nextRow;
currentDSL = {
...currentDSL,
topRow,
bottomRow,
rightColumn,
leftColumn,
};
} catch (error) {
// Sentry.captureException({
// message: "Migrating position of widget on data loss failed",
// oldData: currentDSL,
// });
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((dsl: DSLWidget) =>
migrateWidgetsWithoutLeftRightColumns(dsl, canvasWidgets),
);
}
return currentDSL;
};
export const migrateOverFlowingTabsWidgets = (
currentDSL: DSLWidget,
canvasWidgets: any,
) => {
if (
currentDSL.type === "TABS_WIDGET" &&
currentDSL.version === 3 &&
currentDSL.children &&
currentDSL.children.length
) {
const tabsWidgetHeight =
(currentDSL.bottomRow - currentDSL.topRow) * currentDSL.parentRowSpace;
const widgetHasOverflowingChildren = currentDSL.children.some(
(eachTab: DSLWidget) => {
if (eachTab.children && eachTab.children.length) {
return eachTab.children.some((child: DSLWidget) => {
if (canvasWidgets[child.widgetId].repositioned) {
const tabHeight = child.bottomRow * child.parentRowSpace;
return tabsWidgetHeight < tabHeight;
}
return false;
});
}
return false;
},
);
if (widgetHasOverflowingChildren) {
currentDSL.shouldScrollContents = true;
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((eachChild: DSLWidget) =>
migrateOverFlowingTabsWidgets(eachChild, canvasWidgets),
);
}
return currentDSL;
};

View File

@ -0,0 +1,17 @@
import type { DSLWidget } from "../types";
export const migrateTableWidgetParentRowSpaceProperty = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
if (child.parentRowSpace === 40) {
child.parentRowSpace = 10; //GridDefaults.DEFAULT_GRID_ROW_HEIGHT;
}
} else if (child.children && child.children.length > 0) {
child = migrateTableWidgetParentRowSpaceProperty(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,35 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { get, set } from "lodash";
import type { DSLWidget } from "../types";
export const addLogBlackListToAllListWidgetChildren = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((children: DSLWidget) => {
if (children.type === "LIST_WIDGET") {
const widgets = get(
children,
"children.0.children.0.children.0.children",
);
widgets.map((widget: any, index: number) => {
const logBlackList: { [key: string]: boolean } = {};
Object.keys(widget).map((key) => {
logBlackList[key] = true;
});
if (!widget.logBlackList) {
set(
children,
`children.0.children.0.children.0.children.${index}.logBlackList`,
logBlackList,
);
}
});
}
return children;
});
return currentDSL;
};

View File

@ -0,0 +1,20 @@
import type { DSLWidget } from "../types";
export const migrateTableWidgetHeaderVisibilityProperties = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
if (!("isVisibleSearch" in child)) {
child.isVisibleSearch = true;
child.isVisibleFilters = true;
child.isVisibleDownload = true;
child.isVisiblePagination = true;
}
} else if (child.children && child.children.length > 0) {
child = migrateTableWidgetHeaderVisibilityProperties(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,69 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { DSLWidget } from "../types";
import get from "lodash/get";
import isString from "lodash/isString";
import set from "lodash/set";
const renameKeyInObject = (object: any, key: string, newKey: string) => {
if (object[key]) {
set(object, newKey, object[key]);
}
return object;
};
/**
* changes items -> listData
*
* @param currentDSL
* @returns
*/
export const migrateItemsToListDataInListWidget = (currentDSL: DSLWidget) => {
if (currentDSL.type === "LIST_WIDGET") {
currentDSL = renameKeyInObject(currentDSL, "items", "listData");
currentDSL.dynamicBindingPathList = currentDSL.dynamicBindingPathList?.map(
(path: { key: string }) => {
if (path.key === "items") {
return { key: "listData" };
}
return path;
},
);
currentDSL.dynamicBindingPathList?.map((path: { key: string }) => {
if (
get(currentDSL, path.key) &&
path.key !== "items" &&
path.key !== "listData" &&
isString(get(currentDSL, path.key))
) {
set(
currentDSL,
path.key,
get(currentDSL, path.key, "").replace("items", "listData"),
);
}
});
Object.keys(currentDSL.template).map((widgetName) => {
const currentWidget = currentDSL.template[widgetName];
currentWidget.dynamicBindingPathList?.map((path: { key: string }) => {
set(
currentWidget,
path.key,
get(currentWidget, path.key).replace("items", "listData"),
);
});
});
}
if (currentDSL.children && currentDSL.children.length > 0) {
currentDSL.children = currentDSL.children.map(
migrateItemsToListDataInListWidget,
);
}
return currentDSL;
};

View File

@ -0,0 +1,18 @@
import type { DSLWidget } from "../types";
export const migrateDatePickerMinMaxDate = (currentDSL: DSLWidget) => {
if (currentDSL.type === "DATE_PICKER_WIDGET2" && currentDSL.version === 2) {
if (currentDSL.minDate === "2001-01-01 00:00") {
currentDSL.minDate = "1920-12-31T18:30:00.000Z";
}
if (currentDSL.maxDate === "2041-12-31 23:59") {
currentDSL.maxDate = "2121-12-31T18:29:00.000Z";
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children.map((eachWidgetDSL: DSLWidget) => {
migrateDatePickerMinMaxDate(eachWidgetDSL);
});
}
return currentDSL;
};

View File

@ -0,0 +1,20 @@
import type { DSLWidget } from "../types";
const addFilterDefaultValue = (currentDSL: DSLWidget) => {
if (currentDSL.type === "DROP_DOWN_WIDGET") {
if (!currentDSL.hasOwnProperty("isFilterable")) {
currentDSL.isFilterable = true;
}
}
return currentDSL;
};
export const migrateFilterValueForDropDownWidget = (currentDSL: DSLWidget) => {
const newDSL = addFilterDefaultValue(currentDSL);
newDSL.children = newDSL.children?.map((children: DSLWidget) => {
return migrateFilterValueForDropDownWidget(children);
});
return newDSL;
};

View File

@ -0,0 +1,45 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { DSLWidget } from "../types";
import { removeSpecialChars } from "../utils";
export const migrateTablePrimaryColumnsComputedValue = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
if (
child.primaryColumns &&
Object.keys(child.primaryColumns).length > 0
) {
const newPrimaryColumns: Record<string, any> = {};
for (const [key, value] of Object.entries(
child.primaryColumns as Record<string, any>,
)) {
const sanitizedKey = removeSpecialChars(key, 200);
let newComputedValue = "";
if (value.computedValue) {
newComputedValue = value.computedValue.replace(
`${child.widgetName}.sanitizedTableData.map((currentRow) => { return`,
`${child.widgetName}.sanitizedTableData.map((currentRow) => (`,
);
// change matching "}" bracket with ")"
const lastParanthesesInd = newComputedValue.length - 4;
newComputedValue =
newComputedValue.substring(0, lastParanthesesInd) +
")" +
newComputedValue.substring(lastParanthesesInd + 1);
}
newPrimaryColumns[sanitizedKey] = {
...value,
computedValue: newComputedValue,
};
}
child.primaryColumns = newPrimaryColumns;
}
} else if (child.children && child.children.length > 0) {
child = migrateTablePrimaryColumnsComputedValue(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,17 @@
import type { DSLWidget } from "../types";
export const migrateToNewMultiSelect = (currentDSL: DSLWidget) => {
if (currentDSL.type === "DROP_DOWN_WIDGET") {
if (currentDSL.selectionType === "MULTI_SELECT") {
currentDSL.type = "MULTI_SELECT_WIDGET";
delete currentDSL.isFilterable;
}
delete currentDSL.selectionType;
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((child: DSLWidget) =>
migrateToNewMultiSelect(child),
);
}
return currentDSL;
};

View File

@ -0,0 +1,17 @@
import type { DSLWidget } from "../types";
export const migrateTableWidgetDelimiterProperties = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
if (!child.delimiter) {
child.delimiter = ",";
}
} else if (child.children && child.children.length > 0) {
child = migrateTableWidgetDelimiterProperties(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,31 @@
import type { ColumnProperties, DSLWidget } from "../types";
import isEmpty from "lodash/isEmpty";
const addIsDisabledToButtonColumn = (currentDSL: DSLWidget) => {
if (currentDSL.type === "TABLE_WIDGET") {
if (!isEmpty(currentDSL.primaryColumns)) {
for (const key of Object.keys(
currentDSL.primaryColumns as Record<string, ColumnProperties>,
)) {
if (currentDSL.primaryColumns[key].columnType === "button") {
if (!currentDSL.primaryColumns[key].hasOwnProperty("isDisabled")) {
currentDSL.primaryColumns[key]["isDisabled"] = false;
}
}
if (!currentDSL.primaryColumns[key].hasOwnProperty("isCellVisible")) {
currentDSL.primaryColumns[key]["isCellVisible"] = true;
}
}
}
}
return currentDSL;
};
export const migrateIsDisabledToButtonColumn = (currentDSL: DSLWidget) => {
const newDSL = addIsDisabledToButtonColumn(currentDSL);
newDSL.children = newDSL.children?.map((children: DSLWidget) => {
return migrateIsDisabledToButtonColumn(children);
});
return currentDSL;
};

View File

@ -0,0 +1,13 @@
import type { DSLWidget } from "../types";
export const migrateTableDefaultSelectedRow = (currentDSL: DSLWidget) => {
if (currentDSL.type === "TABLE_WIDGET") {
if (!currentDSL.defaultSelectedRow) currentDSL.defaultSelectedRow = "0";
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((child: DSLWidget) =>
migrateTableDefaultSelectedRow(child),
);
}
return currentDSL;
};

View File

@ -0,0 +1,19 @@
import type { DSLWidget } from "../types";
export const migrateMenuButtonWidgetButtonProperties = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "MENU_BUTTON_WIDGET") {
if (!("menuStyle" in child)) {
child.menuStyle = "PRIMARY";
child.menuVariant = "SOLID";
child.isVisible = true;
}
} else if (child.children && child.children.length > 0) {
child = migrateMenuButtonWidgetButtonProperties(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,16 @@
import has from "lodash/has";
import type { DSLWidget } from "../types";
export const migrateButtonWidgetValidation = (currentDSL: DSLWidget) => {
if (currentDSL.type === "INPUT_WIDGET") {
if (!has(currentDSL, "validation")) {
currentDSL.validation = true;
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children.map((eachWidgetDSL: DSLWidget) => {
migrateButtonWidgetValidation(eachWidgetDSL);
});
}
return currentDSL;
};

View File

@ -0,0 +1,22 @@
import type { DSLWidget } from "../types";
import has from "lodash/has";
export const migrateInputValidation = (currentDSL: DSLWidget) => {
if (currentDSL.type === "INPUT_WIDGET") {
if (has(currentDSL, "validation")) {
// convert boolean to string expression
if (typeof currentDSL.validation === "boolean") {
currentDSL.validation = String(currentDSL.validation);
} else if (typeof currentDSL.validation !== "string") {
// for any other type of value set to default undefined
currentDSL.validation = undefined;
}
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((child: DSLWidget) =>
migrateInputValidation(child),
);
}
return currentDSL;
};

View File

@ -0,0 +1,16 @@
import type { DSLWidget } from "../types";
export const revertTableDefaultSelectedRow = (currentDSL: DSLWidget) => {
if (currentDSL.type === "TABLE_WIDGET") {
if (currentDSL.version === 1 && currentDSL.defaultSelectedRow === "0")
currentDSL.defaultSelectedRow = undefined;
// update version to 3 for all table dsl
currentDSL.version = 3;
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((child: DSLWidget) =>
revertTableDefaultSelectedRow(child),
);
}
return currentDSL;
};

View File

@ -0,0 +1,113 @@
import type { ColumnProperties, DSLWidget } from "../types";
import { removeSpecialChars } from "../utils";
const getSubstringBetweenTwoWords = (
str: string,
startWord: string,
endWord: string,
) => {
const endIndexOfStartWord = str.indexOf(startWord) + startWord.length;
const startIndexOfEndWord = str.lastIndexOf(endWord);
if (startIndexOfEndWord < endIndexOfStartWord) return "";
return str.substring(startIndexOfEndWord, endIndexOfStartWord);
};
/**
* This migration sanitizes the following properties -
* primaryColumns object key, for the value of each key - id, computedValue are sanitized
* columnOrder
* dynamicBindingPathList
*
* This migration solves the following issue -
* https://github.com/appsmithorg/appsmith/issues/6897
*/
export const migrateTableSanitizeColumnKeys = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
const primaryColumnEntries: [string, ColumnProperties][] = Object.entries(
child.primaryColumns || {},
);
const newPrimaryColumns: Record<string, ColumnProperties> = {};
if (primaryColumnEntries.length) {
for (const [, primaryColumnEntry] of primaryColumnEntries.entries()) {
// Value is reassigned when its invalid(Faulty DSL https://github.com/appsmithorg/appsmith/issues/8979)
const [key] = primaryColumnEntry;
let [, value] = primaryColumnEntry;
const sanitizedKey = removeSpecialChars(key, 200);
let id = "";
if (value.id) {
id = removeSpecialChars(value.id, 200);
}
// When id is undefined it's likely value isn't correct and needs fixing
else if (Object.keys(value)) {
const onlyKey = Object.keys(value)[0] as keyof ColumnProperties;
const obj: ColumnProperties = value[onlyKey];
if (!obj.id && !obj.columnType) {
continue;
}
value = obj;
id = removeSpecialChars(value.id, 200);
}
// Sanitizes "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow.$$$random_header))}}"
// to "{{Table1.sanitizedTableData.map((currentRow) => ( currentRow._random_header))}}"
const computedValue = (value?.computedValue || "").replace(
key,
sanitizedKey,
);
newPrimaryColumns[sanitizedKey] = {
...value,
computedValue,
id,
};
}
child.primaryColumns = newPrimaryColumns;
}
// Sanitizes [ "id", "name", $$$random_header ]
// to [ "id", "name", _random_header ]
child.columnOrder = (child.columnOrder || []).map((co: string) =>
removeSpecialChars(co, 200),
);
// Sanitizes [ {key: primaryColumns.$random.header.computedValue }]
// to [ {key: primaryColumns._random_header.computedValue }]
child.dynamicBindingPathList = (child.dynamicBindingPathList || []).map(
(path: { key: string }) => {
const pathChunks = path.key.split("."); // primaryColumns.$random.header.computedValue -> [ "primaryColumns", "$random", "header", "computedValue"]
// tableData is a valid dynamicBindingPath and pathChunks would have just one entry
if (pathChunks.length < 2) {
return path;
}
const firstPart = pathChunks[0] + "."; // "primaryColumns."
const lastPart = "." + pathChunks[pathChunks.length - 1]; // ".computedValue"
const key = getSubstringBetweenTwoWords(
path.key,
firstPart,
lastPart,
); // primaryColumns.$random.header.computedValue -> $random.header
const sanitizedPrimaryColumnKey = removeSpecialChars(key, 200);
return {
key: firstPart + sanitizedPrimaryColumnKey + lastPart,
};
},
);
} else if (child.children && child.children.length > 0) {
child = migrateTableSanitizeColumnKeys(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,33 @@
import type { DSLWidget } from "../types";
const DEFAULT_GRID_ROW_HEIGHT = 10;
export const migrateResizableModalWidgetProperties = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "MODAL_WIDGET" && child.version === 1) {
const size = child.size;
switch (size) {
case "MODAL_SMALL":
child.width = 456;
child.height = DEFAULT_GRID_ROW_HEIGHT * 24;
break;
case "MODAL_LARGE":
child.width = 532;
child.height = DEFAULT_GRID_ROW_HEIGHT * 60;
break;
default:
child.width = 456;
child.height = DEFAULT_GRID_ROW_HEIGHT * 24;
break;
}
child.version = 2;
delete child.size;
} else if (child.children && child.children.length > 0) {
child = migrateResizableModalWidgetProperties(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,50 @@
import type { ColumnProperties, DSLWidget } from "../types";
import { removeSpecialChars } from "../utils";
const getUpdatedColumns = (
widgetName: string,
columns: Record<string, ColumnProperties>,
) => {
const updatedColumns: Record<string, ColumnProperties> = {};
if (columns && Object.keys(columns).length > 0) {
for (const [columnId, columnProps] of Object.entries(columns)) {
const sanitizedColumnId = removeSpecialChars(columnId, 200);
const selectedRowBindingValue = `${widgetName}.selectedRow`;
let newOnClickBindingValue = undefined;
if (
columnProps.onClick &&
columnProps.onClick.includes(selectedRowBindingValue)
) {
newOnClickBindingValue = columnProps.onClick.replace(
selectedRowBindingValue,
"currentRow",
);
}
updatedColumns[sanitizedColumnId] = columnProps;
if (newOnClickBindingValue)
updatedColumns[sanitizedColumnId].onClick = newOnClickBindingValue;
}
}
return updatedColumns;
};
export const migrateTableWidgetSelectedRowBindings = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
child.derivedColumns = getUpdatedColumns(
child.widgetName,
child.derivedColumns as Record<string, ColumnProperties>,
);
child.primaryColumns = getUpdatedColumns(
child.widgetName,
child.primaryColumns as Record<string, ColumnProperties>,
);
} else if (child.children && child.children.length > 0) {
child = migrateTableWidgetSelectedRowBindings(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,103 @@
import type { DSLWidget } from "../types";
export enum ButtonStyleTypes {
PRIMARY = "PRIMARY",
WARNING = "WARNING",
DANGER = "DANGER",
INFO = "INFO",
SECONDARY = "SECONDARY",
CUSTOM = "CUSTOM",
}
const Colors = {
DANGER_SOLID: "#F22B2B",
GREEN: "#03B365",
WARNING_SOLID: "#FEB811",
INFO_SOLID: "#6698FF",
GRAY: "#858282",
};
export const revertButtonStyleToButtonColor = (currentDSL: DSLWidget) => {
if (
currentDSL.type === "BUTTON_WIDGET" ||
currentDSL.type === "FORM_BUTTON_WIDGET" ||
currentDSL.type === "ICON_BUTTON_WIDGET"
) {
if (currentDSL.hasOwnProperty("buttonStyle")) {
switch (currentDSL.buttonStyle) {
case ButtonStyleTypes.DANGER:
currentDSL.buttonColor = Colors.DANGER_SOLID;
break;
case ButtonStyleTypes.PRIMARY:
currentDSL.buttonColor = Colors.GREEN;
break;
case ButtonStyleTypes.WARNING:
currentDSL.buttonColor = Colors.WARNING_SOLID;
break;
case ButtonStyleTypes.INFO:
currentDSL.buttonColor = Colors.INFO_SOLID;
break;
case ButtonStyleTypes.SECONDARY:
currentDSL.buttonColor = Colors.GRAY;
break;
case "PRIMARY_BUTTON":
currentDSL.buttonColor = Colors.GREEN;
break;
case "SECONDARY_BUTTON":
currentDSL.buttonColor = Colors.GREEN;
currentDSL.buttonVariant = "SECONDARY";
break;
case "DANGER_BUTTON":
currentDSL.buttonColor = Colors.DANGER_SOLID;
break;
default:
if (!currentDSL.buttonColor) currentDSL.buttonColor = Colors.GREEN;
break;
}
delete currentDSL.buttonStyle;
}
}
if (currentDSL.type === "MENU_BUTTON_WIDGET") {
if (currentDSL.hasOwnProperty("menuStyle")) {
switch (currentDSL.menuStyle) {
case ButtonStyleTypes.DANGER:
currentDSL.menuColor = Colors.DANGER_SOLID;
break;
case ButtonStyleTypes.PRIMARY:
currentDSL.menuColor = Colors.GREEN;
break;
case ButtonStyleTypes.WARNING:
currentDSL.menuColor = Colors.WARNING_SOLID;
break;
case ButtonStyleTypes.INFO:
currentDSL.menuColor = Colors.INFO_SOLID;
break;
case ButtonStyleTypes.SECONDARY:
currentDSL.menuColor = Colors.GRAY;
break;
default:
if (!currentDSL.menuColor) currentDSL.menuColor = Colors.GREEN;
break;
}
delete currentDSL.menuStyle;
delete currentDSL.prevMenuStyle;
}
}
if (currentDSL.type === "TABLE_WIDGET") {
if (currentDSL.hasOwnProperty("primaryColumns")) {
Object.keys(currentDSL.primaryColumns).forEach((column) => {
if (currentDSL.primaryColumns[column].columnType === "button") {
currentDSL.primaryColumns[column].buttonColor =
currentDSL.primaryColumns[column].buttonStyle;
delete currentDSL.primaryColumns[column].buttonStyle;
}
});
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((child: DSLWidget) =>
revertButtonStyleToButtonColor(child),
);
}
return currentDSL;
};

View File

@ -0,0 +1,62 @@
import type { DSLWidget } from "../types";
enum ButtonVariantTypes {
PRIMARY = "PRIMARY",
SECONDARY = "SECONDARY",
TERTIARY = "TERTIARY",
}
export const migrateButtonVariant = (currentDSL: DSLWidget) => {
if (
currentDSL.type === "BUTTON_WIDGET" ||
currentDSL.type === "FORM_BUTTON_WIDGET" ||
currentDSL.type === "ICON_BUTTON_WIDGET"
) {
switch (currentDSL.buttonVariant) {
case "OUTLINE":
currentDSL.buttonVariant = ButtonVariantTypes.SECONDARY;
break;
case "GHOST":
currentDSL.buttonVariant = ButtonVariantTypes.TERTIARY;
break;
default:
currentDSL.buttonVariant = ButtonVariantTypes.PRIMARY;
}
}
if (currentDSL.type === "MENU_BUTTON_WIDGET") {
switch (currentDSL.menuVariant) {
case "OUTLINE":
currentDSL.menuVariant = ButtonVariantTypes.SECONDARY;
break;
case "GHOST":
currentDSL.menuVariant = ButtonVariantTypes.TERTIARY;
break;
default:
currentDSL.menuVariant = ButtonVariantTypes.PRIMARY;
}
}
if (currentDSL.type === "TABLE_WIDGET") {
if (currentDSL.hasOwnProperty("primaryColumns")) {
Object.keys(currentDSL.primaryColumns).forEach((column) => {
if (currentDSL.primaryColumns[column].columnType === "iconButton") {
let newVariant = ButtonVariantTypes.PRIMARY;
switch (currentDSL.primaryColumns[column].buttonVariant) {
case "OUTLINE":
newVariant = ButtonVariantTypes.SECONDARY;
break;
case "GHOST":
newVariant = ButtonVariantTypes.TERTIARY;
break;
}
currentDSL.primaryColumns[column].buttonVariant = newVariant;
}
});
}
}
if (currentDSL.children && currentDSL.children.length) {
currentDSL.children = currentDSL.children.map((child: DSLWidget) =>
migrateButtonVariant(child),
);
}
return currentDSL;
};

View File

@ -0,0 +1,17 @@
import type { DSLWidget } from "../types";
export const migrateMapWidgetIsClickedMarkerCentered = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "MAP_WIDGET") {
if (!("isClickedMarkerCentered" in child)) {
child.isClickedMarkerCentered = true;
}
} else if (child.children && child.children.length > 0) {
child = migrateMapWidgetIsClickedMarkerCentered(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,17 @@
import type { DSLWidget } from "../types";
export const mapAllowHorizontalScrollMigration = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "CHART_WIDGET") {
child.allowScroll = child.allowHorizontalScroll;
delete child.allowHorizontalScroll;
}
if (Array.isArray(child.children) && child.children.length > 0)
child = mapAllowHorizontalScrollMigration(child);
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,13 @@
import type { DSLWidget } from "../types";
export const isSortableMigration = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET" && !child.hasOwnProperty("isSortable")) {
child["isSortable"] = true;
} else if (child.children && child.children.length > 0) {
child = isSortableMigration(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,25 @@
import type { ColumnProperties, DSLWidget } from "../types";
export const migrateTableWidgetIconButtonVariant = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET") {
const primaryColumns = child.primaryColumns as Record<
string,
ColumnProperties
>;
Object.keys(primaryColumns).forEach((accessor: string) => {
const primaryColumn = primaryColumns[accessor];
if (primaryColumn.columnType === "iconButton") {
if (!("buttonVariant" in primaryColumn)) {
primaryColumn.buttonVariant = "TERTIARY";
}
}
});
} else if (child.children && child.children.length > 0) {
child = migrateTableWidgetIconButtonVariant(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,18 @@
import type { DSLWidget } from "../types";
export const migrateCheckboxGroupWidgetInlineProperty = (
currentDSL: DSLWidget,
) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "CHECKBOX_GROUP_WIDGET") {
if (child.version === 1) {
child.isInline = true;
child.version = 2;
}
} else if (child.children && child.children.length > 0) {
child = migrateCheckboxGroupWidgetInlineProperty(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,3 @@
// We're skipping this to fix a bad table migration.
// skipped migration is added as version 51
export {};

View File

@ -0,0 +1,19 @@
import type { DSLWidget } from "../types";
export const migrateRecaptchaType = (currentDSL: DSLWidget): DSLWidget => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "BUTTON_WIDGET" || child.type === "FORM_BUTTON_WIDGET") {
const recaptchaV2 = child.recaptchaV2;
if (recaptchaV2) {
child.recaptchaType = "V2";
} else {
child.recaptchaType = "V3";
}
delete child.recaptchaV2;
} else if (child.children && child.children.length > 0) {
child = migrateRecaptchaType(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,27 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import set from "lodash/set";
import type { DSLWidget } from "../types";
/**
* adds 'privateWidgets' key for all list widgets
*
* @param currentDSL
* @returns
*/
export const addPrivateWidgetsToAllListWidgets = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "LIST_WIDGET") {
const privateWidgets: any = {};
Object.keys(child.template).forEach((entityName) => {
privateWidgets[entityName] = true;
});
if (!child.privateWidgets) {
set(child, `privateWidgets`, privateWidgets);
}
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,5 @@
/*
* We're skipping this to fix a bad table migration - migrateTableWidgetNumericColumnName
* it overwrites the computedValue of the table columns
*/
export {};

View File

@ -0,0 +1,15 @@
import type { DSLWidget } from "../types";
export const migratePhoneInputWidgetAllowFormatting = (
currentDSL: DSLWidget,
): DSLWidget => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "PHONE_INPUT_WIDGET") {
child.allowFormatting = true;
} else if (child.children && child.children.length > 0) {
child = migratePhoneInputWidgetAllowFormatting(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,17 @@
import type { DSLWidget } from "../types";
export const migrateModalIconButtonWidget = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "ICON_WIDGET") {
child.type = "ICON_BUTTON_WIDGET";
child.buttonColor = "#2E3D49"; // Colors.OXFORD_BLUE;
child.buttonVariant = "TERTIARY";
child.borderRadius = "SHARP";
child.color = undefined;
} else if (child.children && child.children.length > 0) {
child = migrateModalIconButtonWidget(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,29 @@
import type { DSLWidget } from "../types";
export enum OverflowTypes {
SCROLL = "SCROLL",
TRUNCATE = "TRUNCATE",
NONE = "NONE",
}
export const migrateScrollTruncateProperties = (
currentDSL: DSLWidget,
): DSLWidget => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TEXT_WIDGET") {
if (child.shouldTruncate) {
child.overflow = OverflowTypes.TRUNCATE;
} else if (child.shouldScroll) {
child.overflow = OverflowTypes.SCROLL;
} else {
child.overflow = OverflowTypes.NONE;
}
delete child.shouldScroll;
delete child.shouldTruncate;
} else if (child.children && child.children.length > 0) {
child = migrateScrollTruncateProperties(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,32 @@
import type { DSLWidget } from "../types";
export const migratePhoneInputWidgetDefaultDialCode = (
currentDSL: DSLWidget,
): DSLWidget => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "PHONE_INPUT_WIDGET") {
child.defaultDialCode = child.dialCode;
delete child.dialCode;
if (child.dynamicPropertyPathList) {
child.dynamicPropertyPathList.forEach((property: { key: string }) => {
if (property.key === "dialCode") {
property.key = "defaultDialCode";
}
});
}
if (child.dynamicBindingPathList) {
child.dynamicBindingPathList.forEach((property: { key: string }) => {
if (property.key === "dialCode") {
property.key = "defaultDialCode";
}
});
}
} else if (child.children && child.children.length > 0) {
child = migratePhoneInputWidgetDefaultDialCode(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,32 @@
import type { DSLWidget } from "../types";
export const migrateCurrencyInputWidgetDefaultCurrencyCode = (
currentDSL: DSLWidget,
): DSLWidget => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "CURRENCY_INPUT_WIDGET") {
child.defaultCurrencyCode = child.currencyCode;
delete child.currencyCode;
if (child.dynamicPropertyPathList) {
child.dynamicPropertyPathList.forEach((property: { key: string }) => {
if (property.key === "currencyCode") {
property.key = "defaultCurrencyCode";
}
});
}
if (child.dynamicBindingPathList) {
child.dynamicBindingPathList.forEach((property: { key: string }) => {
if (property.key === "currencyCode") {
property.key = "defaultCurrencyCode";
}
});
}
} else if (child.children && child.children.length > 0) {
child = migrateCurrencyInputWidgetDefaultCurrencyCode(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,15 @@
import type { DSLWidget } from "../types";
export const migrateRadioGroupAlignmentProperty = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "RADIO_GROUP_WIDGET") {
if (!child.hasOwnProperty("alignment")) {
child.alignment = "left";
}
} else if (child.children && child.children.length > 0) {
child = migrateRadioGroupAlignmentProperty(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,773 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { clone, get, has, isEmpty, set } from "lodash";
import type { DSLWidget } from "../types";
import { isDynamicValue } from "../utils";
enum ButtonBorderRadiusTypes {
SHARP = "SHARP",
ROUNDED = "ROUNDED",
CIRCLE = "CIRCLE",
}
enum BoxShadowTypes {
NONE = "NONE",
VARIANT1 = "VARIANT1",
VARIANT2 = "VARIANT2",
VARIANT3 = "VARIANT3",
VARIANT4 = "VARIANT4",
VARIANT5 = "VARIANT5",
}
export enum TextSizes {
HEADING1 = "HEADING1",
HEADING2 = "HEADING2",
HEADING3 = "HEADING3",
PARAGRAPH = "PARAGRAPH",
PARAGRAPH2 = "PARAGRAPH2",
}
const THEMING_BORDER_RADIUS = {
none: "0px",
rounded: "0.375rem",
circle: "9999px",
};
const THEMEING_TEXT_SIZES = {
xs: "0.75rem",
sm: "0.875rem",
base: "1rem",
md: "1.125rem",
lg: "1.5rem",
xl: "1.875rem",
"2xl": "3rem",
"3xl": "3.75rem",
};
const rgbaMigrationConstantV56 = "rgba(0, 0, 0, 0.25)";
const DEFAULT_BOXSHADOW = "none";
const ROOT_SCHEMA_KEY = "__root_schema__";
const Colors = {
GREEN: "#03B365",
};
export const BUTTON_GROUP_CHILD_STYLESHEET = {
button: {
buttonColor: "{{appsmith.theme.colors.primaryColor}}",
},
};
export const TABLE_WIDGET_CHILD_STYLESHEET = {
button: {
buttonColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
menuButton: {
menuColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
iconButton: {
menuColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
};
export const JSON_FORM_WIDGET_CHILD_STYLESHEET = {
ARRAY: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
cellBorderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
cellBoxShadow: "none",
},
OBJECT: {
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
cellBorderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
cellBoxShadow: "none",
},
CHECKBOX: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
},
CURRENCY_INPUT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
DATEPICKER: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
EMAIL_INPUT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
MULTISELECT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
MULTILINE_TEXT_INPUT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
NUMBER_INPUT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
PASSWORD_INPUT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
PHONE_NUMBER_INPUT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
RADIO_GROUP: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
boxShadow: "none",
},
SELECT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
SWITCH: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
boxShadow: "none",
},
TEXT_INPUT: {
accentColor: "{{appsmith.theme.colors.primaryColor}}",
borderRadius: "{{appsmith.theme.borderRadius.appBorderRadius}}",
boxShadow: "none",
},
};
/**
* Recursive function to traverse through all the children of the JSON form in theming migration.
* @param schemaItem
* @param propertyPath
* @param callback
*/
export const parseSchemaItem = (
schemaItem: any,
propertyPath: string,
callback: (schemaItem: any, propertyPath: string) => void,
) => {
// Update the theme stuff for this schema
callback(schemaItem, propertyPath);
if (schemaItem && !isEmpty(schemaItem.children)) {
Object.values(schemaItem.children).forEach((schemaItem: any) => {
const childPropertyPath = `${propertyPath}.children.${schemaItem.identifier}`;
parseSchemaItem(schemaItem, childPropertyPath, callback);
});
}
};
/**
* This function will add the given propertyName into the dynamicPropertyPathList.
* @param propertyName
* @param child
*/
export const addPropertyToDynamicPropertyPathList = (
propertyName: string,
child: DSLWidget,
) => {
const isPropertyPathPresent = (child.dynamicPropertyPathList || []).find(
(property: { key: string }) => property.key === propertyName,
);
if (!isPropertyPathPresent) {
child.dynamicPropertyPathList = [
...(child.dynamicPropertyPathList || []),
{ key: propertyName },
];
}
};
export const migrateStylingPropertiesForTheming = (currentDSL: DSLWidget) => {
const widgetsWithPrimaryColorProp = [
"DATE_PICKER_WIDGET2",
"INPUT_WIDGET",
"INPUT_WIDGET_V2",
"LIST_WIDGET",
"MULTI_SELECT_TREE_WIDGET",
"DROP_DOWN_WIDGET",
"TABS_WIDGET",
"SINGLE_SELECT_TREE_WIDGET",
"TABLE_WIDGET",
"BUTTON_GROUP_WIDGET",
"PHONE_INPUT_WIDGET",
"CURRENCY_INPUT_WIDGET",
"SELECT_WIDGET",
"MULTI_SELECT_WIDGET_V2",
"MULTI_SELECT_WIDGET",
];
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
switch (child.borderRadius) {
case ButtonBorderRadiusTypes.SHARP:
child.borderRadius = THEMING_BORDER_RADIUS.none;
break;
case ButtonBorderRadiusTypes.ROUNDED:
child.borderRadius = THEMING_BORDER_RADIUS.rounded;
break;
case ButtonBorderRadiusTypes.CIRCLE:
child.borderRadius = THEMING_BORDER_RADIUS.circle;
addPropertyToDynamicPropertyPathList("borderRadius", child);
break;
default:
if (
(child.type === "CONTAINER_WIDGET" ||
child.type === "FORM_WIDGET" ||
child.type === "JSON_FORM_WIDGET") &&
child.borderRadius
) {
child.borderRadius = `${child.borderRadius}px`;
addPropertyToDynamicPropertyPathList("borderRadius", child);
} else {
child.borderRadius = THEMING_BORDER_RADIUS.none;
}
}
switch (child.boxShadow) {
case BoxShadowTypes.VARIANT1:
child.boxShadow = `0px 0px 4px 3px ${
child.boxShadowColor || "rgba(0, 0, 0, 0.25)"
}`;
addPropertyToDynamicPropertyPathList("boxShadow", child);
break;
case BoxShadowTypes.VARIANT2:
child.boxShadow = `3px 3px 4px ${
child.boxShadowColor || "rgba(0, 0, 0, 0.25)"
}`;
addPropertyToDynamicPropertyPathList("boxShadow", child);
break;
case BoxShadowTypes.VARIANT3:
child.boxShadow = `0px 1px 3px ${
child.boxShadowColor || "rgba(0, 0, 0, 0.25)"
}`;
addPropertyToDynamicPropertyPathList("boxShadow", child);
break;
case BoxShadowTypes.VARIANT4:
child.boxShadow = `2px 2px 0px ${
child.boxShadowColor || "rgba(0, 0, 0, 0.25)"
}`;
addPropertyToDynamicPropertyPathList("boxShadow", child);
break;
case BoxShadowTypes.VARIANT5:
child.boxShadow = `-2px -2px 0px ${
child.boxShadowColor || "rgba(0, 0, 0, 0.25)"
}`;
addPropertyToDynamicPropertyPathList("boxShadow", child);
break;
default:
child.boxShadow = DEFAULT_BOXSHADOW;
}
/**
* Migrates the textSize property present at the table level.
*/
if (child.type === "TABLE_WIDGET") {
switch (child.textSize) {
case TextSizes.PARAGRAPH2:
child.textSize = THEMEING_TEXT_SIZES.xs;
addPropertyToDynamicPropertyPathList("textSize", child);
break;
case TextSizes.PARAGRAPH:
child.textSize = THEMEING_TEXT_SIZES.sm;
break;
case TextSizes.HEADING3:
child.textSize = THEMEING_TEXT_SIZES.base;
break;
case TextSizes.HEADING2:
child.textSize = THEMEING_TEXT_SIZES.md;
addPropertyToDynamicPropertyPathList("textSize", child);
break;
case TextSizes.HEADING1:
child.textSize = THEMEING_TEXT_SIZES.lg;
addPropertyToDynamicPropertyPathList("textSize", child);
break;
default:
child.textSize = THEMEING_TEXT_SIZES.sm;
}
if (child.hasOwnProperty("primaryColumns")) {
Object.keys(child.primaryColumns).forEach((key: string) => {
/**
* Migrates the textSize property present at the primaryColumn and derivedColumn level.
*/
const column = child.primaryColumns[key];
const isDerivedColumn =
child.hasOwnProperty("derivedColumns") &&
key in child.derivedColumns;
const derivedColumn = child.derivedColumns[key];
switch (column.textSize) {
case TextSizes.PARAGRAPH2:
column.textSize = THEMEING_TEXT_SIZES.xs;
if (isDerivedColumn) {
derivedColumn.textSize = THEMEING_TEXT_SIZES.xs;
}
addPropertyToDynamicPropertyPathList(
`primaryColumns.${key}.textSize`,
child,
);
break;
case TextSizes.PARAGRAPH:
column.textSize = THEMEING_TEXT_SIZES.sm;
if (isDerivedColumn) {
derivedColumn.textSize = THEMEING_TEXT_SIZES.sm;
}
break;
case TextSizes.HEADING3:
column.textSize = THEMEING_TEXT_SIZES.base;
if (isDerivedColumn) {
derivedColumn.textSize = THEMEING_TEXT_SIZES.base;
}
break;
case TextSizes.HEADING2:
column.textSize = THEMEING_TEXT_SIZES.md;
if (isDerivedColumn) {
derivedColumn.textSize = THEMEING_TEXT_SIZES.md;
}
addPropertyToDynamicPropertyPathList(
`primaryColumns.${key}.textSize`,
child,
);
break;
case TextSizes.HEADING1:
column.textSize = THEMEING_TEXT_SIZES.lg;
if (isDerivedColumn) {
derivedColumn.textSize = THEMEING_TEXT_SIZES.lg;
}
addPropertyToDynamicPropertyPathList(
`primaryColumns.${key}.textSize`,
child,
);
break;
}
/**
* Migrate the borderRadius if exists for the primary columns and derived columns
*/
if (!column.borderRadius) {
column.borderRadius = THEMING_BORDER_RADIUS.none;
if (isDerivedColumn) {
derivedColumn.borderRadius = THEMING_BORDER_RADIUS.none;
}
}
switch (column.borderRadius) {
case ButtonBorderRadiusTypes.SHARP:
column.borderRadius = THEMING_BORDER_RADIUS.none;
if (isDerivedColumn) {
derivedColumn.borderRadius = THEMING_BORDER_RADIUS.none;
}
break;
case ButtonBorderRadiusTypes.ROUNDED:
column.borderRadius = THEMING_BORDER_RADIUS.rounded;
if (isDerivedColumn) {
derivedColumn.borderRadius = THEMING_BORDER_RADIUS.rounded;
}
break;
case ButtonBorderRadiusTypes.CIRCLE:
column.borderRadius = THEMING_BORDER_RADIUS.circle;
if (isDerivedColumn) {
derivedColumn.borderRadius = THEMING_BORDER_RADIUS.circle;
}
break;
}
/**
* Migrate the boxShadow if exists for the primary columns and derived columns:
*/
const isBoxShadowColorDynamic = isDynamicValue(column.boxShadowColor);
const newBoxShadowColor =
column.boxShadowColor || rgbaMigrationConstantV56;
if (column.boxShadow) {
addPropertyToDynamicPropertyPathList(
`primaryColumns.${key}.boxShadow`,
child,
);
} else {
column.boxShadow = "none";
if (isDerivedColumn) {
derivedColumn.boxShadow = "none";
}
}
switch (column.boxShadow) {
case BoxShadowTypes.VARIANT1:
if (!isBoxShadowColorDynamic) {
// Checks is boxShadowColor is not dynamic
column.boxShadow = `0px 0px 4px 3px ${newBoxShadowColor}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `0px 0px 4px 3px ${newBoxShadowColor}`;
}
delete column.boxShadowColor;
} else {
// Dynamic
column.boxShadow = `0px 0px 4px 3px ${rgbaMigrationConstantV56}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `0px 0px 4px 3px ${rgbaMigrationConstantV56}`;
}
}
break;
case BoxShadowTypes.VARIANT2:
if (!isBoxShadowColorDynamic) {
// Checks is boxShadowColor is not dynamic
column.boxShadow = `3px 3px 4px ${newBoxShadowColor}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `3px 3px 4px ${newBoxShadowColor}`;
}
delete column.boxShadowColor;
} else {
// Dynamic
column.boxShadow = `3px 3px 4px ${rgbaMigrationConstantV56}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `3px 3px 4px ${rgbaMigrationConstantV56}`;
}
}
break;
case BoxShadowTypes.VARIANT3:
if (!isBoxShadowColorDynamic) {
// Checks is boxShadowColor is not dynamic
column.boxShadow = `0px 1px 3px ${newBoxShadowColor}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `0px 1px 3px ${newBoxShadowColor}`;
}
delete column.boxShadowColor;
} else {
// Dynamic
column.boxShadow = `0px 1px 3px ${rgbaMigrationConstantV56}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `0px 1px 3px ${rgbaMigrationConstantV56}`;
}
}
break;
case BoxShadowTypes.VARIANT4:
if (!isBoxShadowColorDynamic) {
// Checks is boxShadowColor is not dynamic
column.boxShadow = `2px 2px 0px ${newBoxShadowColor}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `2px 2px 0px ${newBoxShadowColor}`;
}
delete column.boxShadowColor;
} else {
column.boxShadow = `2px 2px 0px ${rgbaMigrationConstantV56}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `2px 2px 0px ${rgbaMigrationConstantV56}`;
}
}
break;
case BoxShadowTypes.VARIANT5:
if (!isBoxShadowColorDynamic) {
// Checks is boxShadowColor is not dynamic
column.boxShadow = `-2px -2px 0px ${newBoxShadowColor}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `-2px -2px 0px ${newBoxShadowColor}`;
}
delete column.boxShadowColor;
} else {
// Dynamic
column.boxShadow = `-2px -2px 0px ${rgbaMigrationConstantV56}`;
if (isDerivedColumn) {
derivedColumn.boxShadow = `-2px -2px 0px ${rgbaMigrationConstantV56}`;
}
}
break;
}
});
}
}
/**
* Migrate the parent level properties for JSON Form
*/
if (child.type === "JSON_FORM_WIDGET") {
const parentLevelProperties = ["submitButtonStyles", "resetButtonStyles"];
parentLevelProperties.forEach((propertyName: string) => {
const propertyPathBorderRadius = `${propertyName}.borderRadius`;
const propertyPathBoxShadow = `${propertyName}.boxShadow`;
const propertyPathBoxShadowColor = `${propertyName}.boxShadowColor`;
if (has(child, propertyPathBorderRadius)) {
const jsonFormBorderRadius = get(child, propertyPathBorderRadius);
switch (jsonFormBorderRadius) {
case ButtonBorderRadiusTypes.SHARP:
set(child, propertyPathBorderRadius, THEMING_BORDER_RADIUS.none);
break;
case ButtonBorderRadiusTypes.ROUNDED:
set(
child,
propertyPathBorderRadius,
THEMING_BORDER_RADIUS.rounded,
);
break;
case ButtonBorderRadiusTypes.CIRCLE:
set(
child,
propertyPathBorderRadius,
THEMING_BORDER_RADIUS.circle,
);
addPropertyToDynamicPropertyPathList(
propertyPathBorderRadius,
child,
);
break;
default:
set(child, propertyPathBorderRadius, THEMING_BORDER_RADIUS.none);
}
} else {
set(child, propertyPathBorderRadius, THEMING_BORDER_RADIUS.none);
}
if (has(child, propertyPathBoxShadow)) {
const jsonFormBoxShadow = get(child, propertyPathBoxShadow);
const boxShadowColor =
(has(child, propertyPathBoxShadowColor) &&
get(child, propertyPathBoxShadowColor)) ||
"rgba(0, 0, 0, 0.25)";
switch (jsonFormBoxShadow) {
case BoxShadowTypes.VARIANT1:
set(
child,
propertyPathBoxShadow,
`0px 0px 4px 3px ${boxShadowColor}`,
);
addPropertyToDynamicPropertyPathList(
propertyPathBoxShadow,
child,
);
break;
case BoxShadowTypes.VARIANT2:
set(
child,
propertyPathBoxShadow,
`3px 3px 4px ${boxShadowColor}`,
);
addPropertyToDynamicPropertyPathList(
propertyPathBoxShadow,
child,
);
break;
case BoxShadowTypes.VARIANT3:
set(
child,
propertyPathBoxShadow,
`0px 1px 3px ${boxShadowColor}`,
);
addPropertyToDynamicPropertyPathList(
propertyPathBoxShadow,
child,
);
break;
case BoxShadowTypes.VARIANT4:
set(
child,
propertyPathBoxShadow,
`2px 2px 0px ${boxShadowColor}`,
);
addPropertyToDynamicPropertyPathList(
propertyPathBoxShadow,
child,
);
break;
case BoxShadowTypes.VARIANT5:
set(
child,
propertyPathBoxShadow,
`-2px -2px 0px ${boxShadowColor}`,
);
addPropertyToDynamicPropertyPathList(
propertyPathBoxShadow,
child,
);
break;
default:
set(child, propertyPathBoxShadow, DEFAULT_BOXSHADOW);
}
} else {
set(child, propertyPathBoxShadow, DEFAULT_BOXSHADOW);
}
});
/**
* Migrate the children level properties for JSON form
*/
if (has(child, "schema")) {
const clonedSchema = clone(child.schema);
parseSchemaItem(
clonedSchema[ROOT_SCHEMA_KEY],
`schema.${ROOT_SCHEMA_KEY}`,
(schemaItem, propertyPath) => {
if (schemaItem) {
switch (schemaItem.labelTextSize) {
case TextSizes.PARAGRAPH2:
schemaItem.labelTextSize = THEMEING_TEXT_SIZES.xs;
addPropertyToDynamicPropertyPathList(
`${propertyPath}.labelTextSize`,
child,
);
break;
case TextSizes.PARAGRAPH:
schemaItem.labelTextSize = THEMEING_TEXT_SIZES.sm;
break;
case TextSizes.HEADING3:
schemaItem.labelTextSize = THEMEING_TEXT_SIZES.base;
break;
case TextSizes.HEADING2:
schemaItem.labelTextSize = THEMEING_TEXT_SIZES.md;
addPropertyToDynamicPropertyPathList(
`${propertyPath}.labelTextSize`,
child,
);
break;
case TextSizes.HEADING1:
schemaItem.labelTextSize = THEMEING_TEXT_SIZES.lg;
addPropertyToDynamicPropertyPathList(
`${propertyPath}.labelTextSize`,
child,
);
break;
default:
schemaItem.labelTextSize = THEMEING_TEXT_SIZES.sm;
}
// Set the default borderRadius
!has(schemaItem, "borderRadius") &&
set(schemaItem, "borderRadius", THEMING_BORDER_RADIUS.none);
// Set the default borderRadius for the Item styles in an array type:
!has(schemaItem, "cellBorderRadius") &&
set(schemaItem, "cellBorderRadius", THEMING_BORDER_RADIUS.none);
// Sets the default value for the boxShadow
!has(schemaItem, "boxShadow") &&
set(schemaItem, "boxShadow", DEFAULT_BOXSHADOW);
// Sets the default value for the boxShadow property of Item styles inside an array:
!has(schemaItem, "cellBoxShadow") &&
set(schemaItem, "cellBoxShadow", DEFAULT_BOXSHADOW);
// Sets default value as green for the accentColor(Most of the widgets require the below property):
!has(schemaItem, "accentColor") &&
set(schemaItem, "accentColor", Colors.GREEN);
}
},
);
child.schema = clonedSchema;
}
}
switch (child.fontSize) {
case TextSizes.PARAGRAPH2:
child.fontSize = THEMEING_TEXT_SIZES.xs;
addPropertyToDynamicPropertyPathList("fontSize", child);
break;
case TextSizes.PARAGRAPH:
child.fontSize = THEMEING_TEXT_SIZES.sm;
break;
case TextSizes.HEADING3:
child.fontSize = THEMEING_TEXT_SIZES.base;
break;
case TextSizes.HEADING2:
child.fontSize = THEMEING_TEXT_SIZES.md;
addPropertyToDynamicPropertyPathList("fontSize", child);
break;
case TextSizes.HEADING1:
child.fontSize = THEMEING_TEXT_SIZES.lg;
addPropertyToDynamicPropertyPathList("fontSize", child);
break;
}
switch (child.labelTextSize) {
case TextSizes.PARAGRAPH2:
child.labelTextSize = THEMEING_TEXT_SIZES.xs;
addPropertyToDynamicPropertyPathList("labelTextSize", child);
break;
case TextSizes.PARAGRAPH:
child.labelTextSize = THEMEING_TEXT_SIZES.sm;
break;
case TextSizes.HEADING3:
child.labelTextSize = THEMEING_TEXT_SIZES.base;
break;
case TextSizes.HEADING2:
child.labelTextSize = THEMEING_TEXT_SIZES.md;
addPropertyToDynamicPropertyPathList("labelTextSize", child);
break;
case TextSizes.HEADING1:
child.labelTextSize = THEMEING_TEXT_SIZES.lg;
addPropertyToDynamicPropertyPathList("labelTextSize", child);
break;
default:
child.labelTextSize = THEMEING_TEXT_SIZES.sm;
}
/**
* Add primaryColor color to missing widgets
*/
if (widgetsWithPrimaryColorProp.includes(child.type)) {
child.accentColor = "{{appsmith.theme.colors.primaryColor}}";
child.dynamicBindingPathList = [
...(child.dynamicBindingPathList || []),
{
key: "accentColor",
},
];
}
// specific fixes
if (child.type === "AUDIO_RECORDER_WIDGET") {
child.borderRadius = THEMING_BORDER_RADIUS.circle;
child.accentColor = child.backgroundColor;
}
if (child.type === "FILE_PICKER_WIDGET_V2") {
child.buttonColor = Colors.GREEN;
}
if (
child.type === "CHECKBOX_WIDGET" ||
child.type === "CHECKBOX_GROUP_WIDGET" ||
child.type === "SWITCH_WIDGET" ||
child.type === "SWITCH_GROUP_WIDGET"
) {
child.accentColor = Colors.GREEN;
}
if (child.type === "TEXT_WIDGET") {
child.fontFamily = "System Default";
}
// Adds childStyleSheets
switch (child.type) {
case "BUTTON_GROUP_WIDGET":
child.childStylesheet = BUTTON_GROUP_CHILD_STYLESHEET;
break;
case "JSON_FORM_WIDGET":
child.childStylesheet = JSON_FORM_WIDGET_CHILD_STYLESHEET;
break;
case "TABLE_WIDGET":
child.childStylesheet = TABLE_WIDGET_CHILD_STYLESHEET;
break;
}
if (child.children && child.children.length > 0) {
child = migrateStylingPropertiesForTheming(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,29 @@
import type { DSLWidget } from "../types";
export enum AlignWidgetTypes {
LEFT = "LEFT",
RIGHT = "RIGHT",
}
export enum LabelPosition {
Left = "Left",
Right = "Right",
}
export const migrateCheckboxSwitchProperty = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "SWITCH_WIDGET" || child.type === "CHECKBOX_WIDGET") {
if (child.alignWidget === "RIGHT") {
child.alignWidget = AlignWidgetTypes.RIGHT;
child.labelPosition = LabelPosition.Left;
} else {
child.alignWidget = AlignWidgetTypes.LEFT;
child.labelPosition = LabelPosition.Right;
}
} else if (child.children && child.children.length > 0) {
child = migrateCheckboxSwitchProperty(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,31 @@
import type { DSLWidget } from "../types";
export const migrateChartWidgetReskinningData = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "CHART_WIDGET") {
if (
!(
child.hasOwnProperty("accentColor") &&
child.hasOwnProperty("fontFamily")
)
) {
child.accentColor = "{{appsmith.theme.colors.primaryColor}}";
child.fontFamily = "{{appsmith.theme.fontFamily.appFont}}";
child.dynamicBindingPathList = [
...(child.dynamicBindingPathList || []),
{
key: "accentColor",
},
{
key: "fontFamily",
},
];
}
} else if (child.children && child.children.length > 0) {
child = migrateChartWidgetReskinningData(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,23 @@
import type { DSLWidget } from "../types";
/*
* Adds validation object to each column in the primaryColumns
*/
export const migrateTableWidgetV2Validation = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "TABLE_WIDGET_V2") {
const primaryColumns = child.primaryColumns;
for (const key in primaryColumns) {
if (primaryColumns.hasOwnProperty(key)) {
primaryColumns[key].validation = {};
}
}
} else if (child.children && child.children.length > 0) {
child = migrateTableWidgetV2Validation(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,3 @@
// this is a repeat of the migration 059-migrate-chart-widget-reskinning-data
export {};

View File

@ -0,0 +1,38 @@
import type { DSLWidget } from "../types";
import { isDynamicValue, stringToJS } from "../utils";
const getBindingTemplate = (widgetName: string) => {
const prefixTemplate = `{{ ((options, serverSideFiltering) => ( `;
const suffixTemplate = `))(${widgetName}.options, ${widgetName}.serverSideFiltering) }}`;
return { prefixTemplate, suffixTemplate };
};
const SelectTypeWidgets = ["SELECT_WIDGET", "MULTI_SELECT_WIDGET_V2"];
export function MigrateSelectTypeWidgetDefaultValue(currentDSL: DSLWidget) {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (SelectTypeWidgets.includes(child.type)) {
const defaultOptionValue = child.defaultOptionValue;
const { prefixTemplate, suffixTemplate } = getBindingTemplate(
child.widgetName,
);
if (
typeof defaultOptionValue === "string" &&
isDynamicValue(defaultOptionValue) &&
!defaultOptionValue.endsWith(suffixTemplate) &&
!defaultOptionValue.startsWith(prefixTemplate)
) {
child.defaultOptionValue = `${prefixTemplate}${stringToJS(
defaultOptionValue,
)}${suffixTemplate}`;
}
} else if (child.children && child.children.length > 0) {
child = MigrateSelectTypeWidgetDefaultValue(child);
}
return child;
});
return currentDSL;
}

View File

@ -0,0 +1,24 @@
import type { DSLWidget } from "../types";
export const migrateMapChartWidgetReskinningData = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "MAP_CHART_WIDGET") {
if (!child.hasOwnProperty("fontFamily")) {
child.fontFamily = "{{appsmith.theme.fontFamily.appFont}}";
child.dynamicBindingPathList = [
...(child.dynamicBindingPathList || []),
{
key: "fontFamily",
},
];
}
} else if (child.children && child.children.length > 0) {
child = migrateMapChartWidgetReskinningData(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,51 @@
import type { DSLWidget } from "../types";
import { isDynamicValue } from "../utils";
// migrate all rate widgets with isDisabled = true to isReadOnly = true
export function migrateRateWidgetDisabledState(currentDSL: DSLWidget) {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "RATE_WIDGET") {
// if isDisabled is true, set isReadOnly to true
if (child.isDisabled === true) {
child.isDisabled = false;
child.isReadOnly = true;
} else if (
// if isDisabled is a dynamic value, set isReadOnly to the same dynamic value
typeof child.isDisabled === "string" &&
isDynamicValue(child.isDisabled)
) {
child.isReadOnly = child.isDisabled;
child.isDisabled = false;
// add readonly to dynamic binding
child.dynamicBindingPathList = [
...(child.dynamicBindingPathList || []),
{
key: "isReadOnly",
},
];
child.dynamicPropertyPathList = [
...(child.dynamicPropertyPathList || []),
{
key: "isReadOnly",
},
];
// remove readonly from dynamic binding
child.dynamicBindingPathList = child.dynamicBindingPathList.filter(
(item: { key: string }) => item.key !== "isDisabled",
);
child.dynamicPropertyPathList = child.dynamicPropertyPathList.filter(
(item: { key: string }) => item.key !== "isDisabled",
);
}
} else if (child.children && child.children.length > 0) {
child = migrateRateWidgetDisabledState(child);
}
return child;
});
return currentDSL;
}

View File

@ -0,0 +1,17 @@
import type { DSLWidget } from "../types";
export const migrateCodeScannerLayout = (currentDSL: DSLWidget) => {
currentDSL.children = currentDSL.children?.map((child: DSLWidget) => {
if (child.type === "CODE_SCANNER_WIDGET") {
if (!child.scannerLayout) {
child.scannerLayout = "CLICK_TO_SCAN";
}
} else if (child.children && child.children.length > 0) {
child = migrateCodeScannerLayout(child);
}
return child;
});
return currentDSL;
};

View File

@ -0,0 +1,79 @@
import type { DSLWidget, WidgetProps } from "../types";
import { isDynamicValue, traverseDSLAndMigrate } from "../utils";
const oldBindingPrefix = `{{
(
(editedValue, currentRow, currentIndex) => (
`;
const newBindingPrefix = `{{
(
(editedValue, currentRow, currentIndex, isNewRow) => (
`;
const oldBindingSuffix = (tableId: string, columnName: string) => `
))
(
${tableId}.columnEditableCellValue.${columnName} || "",
${tableId}.processedTableData[${tableId}.editableCell.index] ||
Object.keys(${tableId}.processedTableData[0])
.filter(key => ["__originalIndex__", "__primaryKey__"].indexOf(key) === -1)
.reduce((prev, curr) => {
prev[curr] = "";
return prev;
}, {}),
${tableId}.editableCell.index)
}}
`;
const newBindingSuffix = (tableId: string, columnName: string) => {
return `
))
(
(${tableId}.isAddRowInProgress ? ${tableId}.newRow.${columnName} : ${tableId}.columnEditableCellValue.${columnName}) || "",
${tableId}.isAddRowInProgress ? ${tableId}.newRow : (${tableId}.processedTableData[${tableId}.editableCell.index] ||
Object.keys(${tableId}.processedTableData[0])
.filter(key => ["__originalIndex__", "__primaryKey__"].indexOf(key) === -1)
.reduce((prev, curr) => {
prev[curr] = "";
return prev;
}, {})),
${tableId}.isAddRowInProgress ? -1 : ${tableId}.editableCell.index,
${tableId}.isAddRowInProgress
)
}}
`;
};
export const migrateTableWidgetV2ValidationBinding = (
currentDSL: DSLWidget,
) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
const primaryColumns = widget.primaryColumns;
for (const column in primaryColumns) {
if (
primaryColumns.hasOwnProperty(column) &&
primaryColumns[column].validation &&
primaryColumns[column].validation.isColumnEditableCellValid &&
isDynamicValue(
primaryColumns[column].validation.isColumnEditableCellValid,
)
) {
const propertyValue =
primaryColumns[column].validation.isColumnEditableCellValid;
const binding = propertyValue
.replace(oldBindingPrefix, "")
.replace(oldBindingSuffix(widget.widgetName, column), "");
primaryColumns[column].validation.isColumnEditableCellValid =
newBindingPrefix +
binding +
newBindingSuffix(widget.widgetName, column);
}
}
}
});
};

View File

@ -0,0 +1,14 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export function migrateLabelPosition(currentDSL: DSLWidget) {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (
(widget.type === "PHONE_INPUT_WIDGET" ||
widget.type === "CURRENCY_INPUT_WIDGET") &&
widget.labelPosition === undefined
) {
widget.labelPosition = "Left";
}
});
}

View File

@ -0,0 +1,62 @@
import type { DSLWidget } from "../types";
export const WidgetHeightLimits = {
MAX_HEIGHT_IN_ROWS: 9000,
MIN_HEIGHT_IN_ROWS: 4,
MIN_CANVAS_HEIGHT_IN_ROWS: 10,
};
export const WidgetFeatureProps: Record<string, Record<string, unknown>> = {
dynamicHeight: {
minDynamicHeight: WidgetHeightLimits.MIN_HEIGHT_IN_ROWS,
maxDynamicHeight: WidgetHeightLimits.MAX_HEIGHT_IN_ROWS,
dynamicHeight: "FIXED",
},
};
export const migratePropertiesForDynamicHeight = (currentDSL: DSLWidget) => {
/* const widgetsWithDynamicHeight = compact(
ALL_WIDGETS_AND_CONFIG.map(([, config]) => {
if (config.features?.dynamicHeight) return config.type;
}),
); */
// Ideally the above should be the code, however,
// there seems to be some cyclic imports which
// cause the test to fail in CI.
const widgetsWithDynamicHeight = [
"CONTAINER_WIDGET",
"TEXT_WIDGET",
"CHECKBOX_WIDGET",
"RADIO_GROUP_WIDGET",
"TABS_WIDGET",
"MODAL_WIDGET",
"RICH_TEXT_EDITOR_WIDGET",
"DATE_PICKER_WIDGET2",
"SWITCH_WIDGET",
"FORM_WIDGET",
"RATE_WIDGET",
"CHECKBOX_GROUP_WIDGET",
"STATBOX_WIDGET",
"MULTI_SELECT_TREE_WIDGET",
"SINGLE_SELECT_TREE_WIDGET",
"SWITCH_GROUP_WIDGET",
"SELECT_WIDGET",
"MULTI_SELECT_WIDGET_V2",
"INPUT_WIDGET_V2",
"PHONE_INPUT_WIDGET",
"CURRENCY_INPUT_WIDGET",
"JSON_FORM_WIDGET",
];
if (widgetsWithDynamicHeight.includes(currentDSL.type)) {
currentDSL = {
...currentDSL,
...WidgetFeatureProps["dynamicHeight"],
};
}
if (Array.isArray(currentDSL.children)) {
currentDSL.children = currentDSL.children.map(
migratePropertiesForDynamicHeight,
);
}
return currentDSL;
};

View File

@ -0,0 +1,10 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateMenuButtonDynamicItems = (currentDSL: DSLWidget) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "MENU_BUTTON_WIDGET" && !widget.menuItemsSource) {
widget.menuItemsSource = "STATIC";
}
});
};

View File

@ -0,0 +1,23 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateChildStylesheetFromDynamicBindingPathList = (
currentDSL: DSLWidget,
) => {
const widgetsWithChildStylesheet = [
"TABLE_WIDGET_V2",
"BUTTON_GROUP_WIDGET",
"JSON_FORM_WIDGET",
];
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (
widgetsWithChildStylesheet.includes(widget.type) &&
widget.childStylesheet
) {
const newPaths = widget.dynamicBindingPathList?.filter(
({ key }: { key: string }) => !key.startsWith("childStylesheet."),
);
widget.dynamicBindingPathList = newPaths;
}
});
};

View File

@ -0,0 +1,27 @@
import type { DSLWidget, WidgetProps } from "../types";
import { isDynamicValue, stringToJS, traverseDSLAndMigrate } from "../utils";
export const migrateTableWidgetV2SelectOption = (currentDSL: DSLWidget) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
Object.values(
widget.primaryColumns as Record<
string,
{ columnType: string; selectOptions: string }
>,
)
.filter((column) => column.columnType === "select")
.forEach((column) => {
const selectOptions = column.selectOptions;
if (selectOptions && isDynamicValue(selectOptions)) {
column.selectOptions = `{{${
widget.widgetName
}.processedTableData.map((currentRow, currentIndex) => ( ${stringToJS(
selectOptions,
)}))}}`;
}
});
}
});
};

View File

@ -0,0 +1,38 @@
import type { DSLWidget } from "../types";
export function migrateListWidgetChildrenForAutoHeight(
currentDSL: DSLWidget,
isChildOfListWidget = false,
): DSLWidget {
if (!currentDSL) return currentDSL;
let isCurrentListWidget = false;
if (currentDSL.type === "LIST_WIDGET") isCurrentListWidget = true;
//Iterate and recursively call each children
const children = currentDSL.children?.map((childDSL: DSLWidget) =>
migrateListWidgetChildrenForAutoHeight(
childDSL,
isCurrentListWidget || isChildOfListWidget,
),
);
let newDSL;
// Add dynamicHeight to FIXED for each of it's children
if (isChildOfListWidget && !currentDSL.detachFromLayout) {
newDSL = {
...currentDSL,
dynamicHeight: "FIXED",
};
} else {
newDSL = {
...currentDSL,
};
}
if (children) {
newDSL.children = children;
}
return newDSL;
}

View File

@ -0,0 +1,16 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateInputWidgetShowStepArrows = (
currentDSL: DSLWidget,
): DSLWidget => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (
(widget.type === "CURRENCY_INPUT_WIDGET" ||
(widget.type === "INPUT_WIDGET_V2" && widget.inputType === "NUMBER")) &&
widget.showStepArrows === undefined
) {
widget.showStepArrows = true;
}
});
};

View File

@ -0,0 +1,24 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateMenuButtonDynamicItemsInsideTableWidget = (
currentDSL: DSLWidget,
) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
const primaryColumns = widget.primaryColumns;
if (primaryColumns) {
for (const column in primaryColumns) {
if (
primaryColumns.hasOwnProperty(column) &&
primaryColumns[column].columnType === "menuButton" &&
!primaryColumns[column].menuItemsSource
) {
primaryColumns[column].menuItemsSource = "STATIC";
}
}
}
}
});
};

View File

@ -0,0 +1,28 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
const GRID_DENSITY_MIGRATION_V1 = 4;
export function migrateInputWidgetsMultiLineInputType(
currentDSL: DSLWidget,
): DSLWidget {
if (!currentDSL) return currentDSL;
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "INPUT_WIDGET_V2") {
const minInputSingleLineHeight =
widget.label || widget.tooltip
? // adjust height for label | tooltip extra div
GRID_DENSITY_MIGRATION_V1 + 4
: // GRID_DENSITY_MIGRATION_V1 used to adjust code as per new scaled canvas.
GRID_DENSITY_MIGRATION_V1;
const isMultiLine =
(widget.bottomRow - widget.topRow) / minInputSingleLineHeight > 1 &&
widget.inputType === "TEXT";
if (isMultiLine) {
widget.inputType = "MULTI_LINE_TEXT";
}
}
});
}

View File

@ -0,0 +1,22 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateColumnFreezeAttributes = (currentDSL: DSLWidget) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
const primaryColumns = widget?.primaryColumns;
// Assign default sticky value to each column
if (primaryColumns) {
for (const column in primaryColumns) {
if (!primaryColumns[column].hasOwnProperty("sticky")) {
primaryColumns[column].sticky = "";
}
}
}
widget.canFreezeColumn = false;
widget.columnUpdatedAt = Date.now();
}
});
};

View File

@ -0,0 +1,25 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { ColumnPropertiesV2, DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateTableSelectOptionAttributesForNewRow = (
currentDSL: DSLWidget,
) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
const primaryColumns = widget?.primaryColumns as ColumnPropertiesV2;
// Set default value for allowSameOptionsInNewRow
if (primaryColumns) {
Object.values(primaryColumns).forEach((column: any) => {
if (
column.hasOwnProperty("columnType") &&
column.columnType === "select"
) {
column.allowSameOptionsInNewRow = true;
}
});
}
}
});
};

View File

@ -0,0 +1,70 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import type { ColumnPropertiesV2, DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateBindingPrefixSuffixForInlineEditValidationControl = (
currentDSL: DSLWidget,
) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
const tableId = widget.widgetName;
const oldBindingPrefix = `{{((isNewRow)=>(`;
const newBindingPrefix = `{{
(
(isNewRow, currentIndex, currentRow) => (
`;
const oldBindingSuffix = `))(${tableId}.isAddRowInProgress)}}`;
const newBindingSuffix = `
))
(
${tableId}.isAddRowInProgress,
${tableId}.isAddRowInProgress ? -1 : ${tableId}.editableCell.index,
${tableId}.isAddRowInProgress ? ${tableId}.newRow : (${tableId}.processedTableData[${tableId}.editableCell.index] ||
Object.keys(${tableId}.processedTableData[0])
.filter(key => ["__originalIndex__", "__primaryKey__"].indexOf(key) === -1)
.reduce((prev, curr) => {
prev[curr] = "";
return prev;
}, {}))
)
}}
`;
const applicableValidationNames = [
"min",
"max",
"regex",
"errorMessage",
"isColumnEditableCellRequired",
];
const primaryColumns = widget?.primaryColumns as ColumnPropertiesV2;
Object.values(primaryColumns).forEach((column: any) => {
if (column.hasOwnProperty("validation")) {
const validations = column.validation;
for (const validationName in validations) {
if (applicableValidationNames.indexOf(validationName) == -1) {
continue;
}
const validationValue = validations[validationName];
if (typeof validationValue !== "string") {
continue;
}
let compressedValidationValue = validationValue.replace(/\s/g, "");
compressedValidationValue = compressedValidationValue.replace(
oldBindingPrefix,
newBindingPrefix,
);
compressedValidationValue = compressedValidationValue.replace(
oldBindingSuffix,
newBindingSuffix,
);
validations[validationName] = compressedValidationValue;
}
}
});
}
});
};

View File

@ -0,0 +1,18 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateTableWidgetTableDataJsMode = (currentDSL: DSLWidget) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
const dynamicPropertyPathList = (
widget.dynamicPropertyPathList || []
).concat([
{
key: "tableData",
},
]);
widget.dynamicPropertyPathList = dynamicPropertyPathList;
}
});
};

View File

@ -0,0 +1,17 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export function migrateSelectWidgetOptionToSourceData(currentDSL: DSLWidget) {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (
["SELECT_WIDGET", "MULTI_SELECT_WIDGET_V2"].includes(widget.type) &&
widget.options
) {
widget.sourceData = widget.options;
widget.optionLabel = "label";
widget.optionValue = "value";
delete widget.options;
}
});
}

View File

@ -0,0 +1,26 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
/*
* Migration to remove the options from dynamicBindingPathList and replace it with
* sourceData
*/
export function migrateSelectWidgetSourceDataBindingPathList(
currentDSL: DSLWidget,
) {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (["SELECT_WIDGET", "MULTI_SELECT_WIDGET_V2"].includes(widget.type)) {
const dynamicBindingPathList = widget.dynamicBindingPathList;
const optionsIndex = dynamicBindingPathList
?.map((d: { key: string }) => d.key)
.indexOf("options");
if (optionsIndex && optionsIndex > -1) {
dynamicBindingPathList?.splice(optionsIndex, 1, {
key: "sourceData",
});
}
}
});
}

View File

@ -0,0 +1,15 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateChartWidgetLabelOrientationStaggerOption = (
currentDSL: DSLWidget,
) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type == "CHART_WIDGET") {
const chartWidgetProps = widget;
if (chartWidgetProps.labelOrientation == "stagger") {
chartWidgetProps.labelOrientation = "auto";
}
}
});
};

View File

@ -0,0 +1,11 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateAddShowHideDataPointLabels = (currentDSL: DSLWidget) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type == "CHART_WIDGET") {
const chartWidgetProps = widget;
chartWidgetProps.showDataPointLabel = chartWidgetProps.allowScroll;
}
});
};

View File

@ -0,0 +1,31 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
/*
* Migration to add sourceData to the dynamicPropertyPathList
*/
export function migrateSelectWidgetAddSourceDataPropertyPathList(
currentDSL: DSLWidget,
) {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (["SELECT_WIDGET", "MULTI_SELECT_WIDGET_V2"].includes(widget.type)) {
const dynamicPropertyPathList = widget.dynamicPropertyPathList;
const sourceDataIndex = dynamicPropertyPathList
?.map((d: { key: string }) => d.key)
.indexOf("sourceData");
if (sourceDataIndex && sourceDataIndex === -1) {
dynamicPropertyPathList?.push({
key: "sourceData",
});
} else if (!Array.isArray(dynamicPropertyPathList)) {
widget.dynamicPropertyPathList = [
{
key: "sourceData",
},
];
}
}
});
}

View File

@ -0,0 +1,75 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
const DefaultEChartConfig = {
dataset: {
source: [
["Day", "Baidu", "Google", "Bing"],
["Mon", 620, 120, 60],
["Tue", 732, 132, 72],
["Wed", 701, 101, 71],
["Thu", 734, 134, 74],
["Fri", 1090, 290, 190],
["Sat", 1130, 230, 130],
["Sun", 1120, 220, 110],
],
},
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
title: {
text: "Search Engine Usage",
left: "center",
textStyle: {
width: 200,
overflow: "truncate",
},
},
legend: {
top: 40,
type: "scroll",
},
grid: {
left: 15,
right: 15,
bottom: 30,
top: 100,
containLabel: true,
},
xAxis: [
{
type: "category",
},
],
yAxis: [
{
type: "value",
},
],
series: [
{
type: "bar",
stack: "Search Engine",
},
{
type: "bar",
stack: "Search Engine",
},
{
type: "bar",
stack: "Search Engine",
},
],
};
export const migrateDefaultValuesForCustomEChart = (currentDSL: DSLWidget) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type == "CHART_WIDGET") {
const chartWidgetProps = widget;
chartWidgetProps.customEChartConfig = DefaultEChartConfig;
}
});
};

View File

@ -0,0 +1,10 @@
import type { DSLWidget, WidgetProps } from "../types";
import { traverseDSLAndMigrate } from "../utils";
export const migrateTableServerSideFiltering = (currentDSL: DSLWidget) => {
return traverseDSLAndMigrate(currentDSL, (widget: WidgetProps) => {
if (widget.type === "TABLE_WIDGET_V2") {
widget.enableServerSideFiltering = false;
}
});
};

Some files were not shown because too many files have changed in this diff Show More