chore: remove xml parser v3 as a default library (#28012)
## Description Contains the changes to remove fast-xml-parserV3.17.5 as a default library and migrate all existing apps to install it as a custom JS library on page load. Installations no longer fail when there is a naming collision, we determine a unique accessor that can work inside the application both for UMD & ESM builds. #### PR fixes following issue(s) Fixes https://github.com/appsmithorg/appsmith-ee/issues/2562 Fixes https://github.com/appsmithorg/appsmith-ee/issues/2563 Fixes https://github.com/appsmithorg/appsmith-ee/issues/2073 Fixes https://github.com/appsmithorg/appsmith-ee/issues/2403 #### Type of change - Chore (housekeeping or task changes that don't impact user perception) > ## Testing > #### How Has This Been Tested? - [x] Manual - [x] JUnit - [x] Jest - [x] Cypress > > #### Test Plan https://github.com/appsmithorg/TestSmith/issues/2536 Scenarios for existing apps will be tested post-merge since DP's are created with fresh DB that don't have release data > > #### Issues raised during DP testing https://github.com/appsmithorg/appsmith/pull/28012#issuecomment-1767711382 response: https://github.com/appsmithorg/appsmith/pull/28012#issuecomment-1767781029 > > > ## Checklist: #### Dev activity - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my own code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag #### QA activity: - [x] [Speedbreak features](https://github.com/appsmithorg/TestSmith/wiki/Guidelines-for-test-plans#speedbreakers-) have been covered - [x] 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 - [x] 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 - [x] Added `Test Plan Approved` label after Cypress tests were reviewed - [ ] Added `Test Plan Approved` label after JUnit tests were reviewed --------- Co-authored-by: manish kumar <manish@appsmith.com> Co-authored-by: Manish Kumar <107841575+sondermanish@users.noreply.github.com>
This commit is contained in:
parent
17eae14dfc
commit
af9e89d2a1
|
|
@ -86,15 +86,6 @@ describe("Autocomplete bug fixes", function () {
|
|||
);
|
||||
});
|
||||
|
||||
it("6. feat #16426 Autocomplete for fast-xml-parser", function () {
|
||||
entityExplorer.SelectEntityByName("Text1");
|
||||
propPane.TypeTextIntoField("Text", "{{xmlParser.j");
|
||||
agHelper.GetNAssertElementText(locators._hints, "j2xParser");
|
||||
|
||||
propPane.TypeTextIntoField("Text", "{{new xmlParser.j2xParser().p");
|
||||
agHelper.GetNAssertElementText(locators._hints, "parse");
|
||||
});
|
||||
|
||||
it(
|
||||
"excludeForAirgap",
|
||||
"7. Installed library should show up in autocomplete",
|
||||
|
|
|
|||
|
|
@ -3,9 +3,21 @@ import * as _ from "../../../../support/Objects/ObjectsCore";
|
|||
|
||||
describe("xml2json text", function () {
|
||||
before(() => {
|
||||
_.agHelper.AddDsl("xmlParser");
|
||||
_.homePage.NavigateToHome();
|
||||
_.homePage.ImportApp("xmlParser.json");
|
||||
_.homePage.AssertImportToast();
|
||||
});
|
||||
it("1. Publish widget and validate the data displayed in text widget from xmlParser function", function () {
|
||||
|
||||
it("1. Check if XMLparser v3 autocomplete works", function () {
|
||||
_.entityExplorer.SelectEntityByName("Text2", "Widgets");
|
||||
_.propPane.TypeTextIntoField("Text", "{{xmlParser.j", true);
|
||||
_.agHelper.GetNAssertElementText(_.locators._hints, "j2xParser");
|
||||
|
||||
_.propPane.TypeTextIntoField("Text", "{{new xmlParser.j2xParser().p", true);
|
||||
_.agHelper.GetNAssertElementText(_.locators._hints, "parse");
|
||||
});
|
||||
|
||||
it("2. Publish widget and validate the data displayed in text widget from xmlParser function", function () {
|
||||
_.deployMode.DeployApp();
|
||||
cy.get(publish.textWidget)
|
||||
.first()
|
||||
|
|
|
|||
|
|
@ -53,11 +53,13 @@ describe("Import and validate older app (app created in older versions of Appsmi
|
|||
gitSync._gitStatusChanges,
|
||||
/[0-9] page(|s) modified/,
|
||||
);
|
||||
agHelper.GetNAssertElementText(
|
||||
gitSync._gitStatusChanges,
|
||||
"Application settings modified",
|
||||
"not.contain.text",
|
||||
);
|
||||
|
||||
// Commenting it as part of #28012 - to be added back later
|
||||
// agHelper.GetNAssertElementText(
|
||||
// gitSync._gitStatusChanges,
|
||||
// "Application settings modified",
|
||||
// "not.contain.text",
|
||||
// );
|
||||
agHelper.GetNAssertElementText(
|
||||
gitSync._gitStatusChanges,
|
||||
"Theme modified",
|
||||
|
|
@ -73,7 +75,10 @@ describe("Import and validate older app (app created in older versions of Appsmi
|
|||
// );
|
||||
|
||||
agHelper.AssertContains(/[0-9] JS Object(|s) modified/, "not.exist");
|
||||
agHelper.AssertContains(/[0-9] librar(y|ies) modified/, "not.exist");
|
||||
|
||||
// Commenting it as part of #28012 - to be added back later
|
||||
// agHelper.AssertContains(/[0-9] librar(y|ies) modified/, "not.exist");
|
||||
|
||||
agHelper.GetNAssertElementText(
|
||||
gitSync._gitStatusChanges,
|
||||
"Some of the changes above are due to an improved file structure designed to reduce merge conflicts. You can safely commit them to your repository.",
|
||||
|
|
|
|||
|
|
@ -10,14 +10,13 @@ describe("excludeForAirgap", "Tests JS Libraries", () => {
|
|||
_.installer.assertUnInstall("uuidjs");
|
||||
});
|
||||
|
||||
it("2. Checks for naming collision", () => {
|
||||
it("2. Installs the library against a unique namespace when there is a collision with the existing entity", () => {
|
||||
_.entityExplorer.DragDropWidgetNVerify(_.draggableWidgets.TABLE, 200, 200);
|
||||
_.entityExplorer.NavigateToSwitcher("Explorer");
|
||||
_.entityExplorer.RenameEntityFromExplorer("Table1", "jsonwebtoken");
|
||||
_.entityExplorer.ExpandCollapseEntity("Libraries");
|
||||
_.installer.OpenInstaller();
|
||||
_.installer.installLibrary("jsonwebtoken", "jsonwebtoken", false);
|
||||
_.agHelper.AssertContains("Name collision detected: jsonwebtoken");
|
||||
_.installer.installLibrary("jsonwebtoken", "jsonwebtoken_1", true);
|
||||
});
|
||||
|
||||
it("3. Checks jspdf library", () => {
|
||||
|
|
|
|||
|
|
@ -1,64 +1,342 @@
|
|||
{
|
||||
"dsl": {
|
||||
"widgetName": "MainContainer",
|
||||
"backgroundColor": "none",
|
||||
"rightColumn": 1224,
|
||||
"snapColumns": 16,
|
||||
"detachFromLayout": true,
|
||||
"widgetId": "0",
|
||||
"topRow": 0,
|
||||
"bottomRow": 1280,
|
||||
"containerStyle": "none",
|
||||
"snapRows": 33,
|
||||
"parentRowSpace": 1,
|
||||
"type": "CANVAS_WIDGET",
|
||||
"canExtend": true,
|
||||
"version": 7,
|
||||
"minHeight": 1292,
|
||||
"parentColumnSpace": 1,
|
||||
"leftColumn": 0,
|
||||
"dynamicBindingPathList": [],
|
||||
"children": [
|
||||
"clientSchemaVersion": 1.0,
|
||||
"serverSchemaVersion": 6.0,
|
||||
"exportedApplication": {
|
||||
"name": "xml_paser_test",
|
||||
"isPublic": false,
|
||||
"pages": [
|
||||
{
|
||||
"isVisible": true,
|
||||
"text": "{{xmlParser.parse(Input1.text) }}",
|
||||
"textStyle": "LABEL",
|
||||
"textAlign": "LEFT",
|
||||
"widgetName": "Text1",
|
||||
"type": "TEXT_WIDGET",
|
||||
"isLoading": false,
|
||||
"parentColumnSpace": 74,
|
||||
"parentRowSpace": 40,
|
||||
"leftColumn": 3,
|
||||
"rightColumn": 8,
|
||||
"topRow": 3,
|
||||
"bottomRow": 10,
|
||||
"parentId": "0",
|
||||
"widgetId": "axlcnmjk4t",
|
||||
"dynamicBindingPathList": [
|
||||
{
|
||||
"key": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"isVisible": true,
|
||||
"inputType": "TEXT",
|
||||
"label": "",
|
||||
"widgetName": "Input1",
|
||||
"type": "INPUT_WIDGET_V2",
|
||||
"isLoading": false,
|
||||
"parentColumnSpace": 74,
|
||||
"parentRowSpace": 40,
|
||||
"leftColumn": 3,
|
||||
"rightColumn": 8,
|
||||
"topRow": 2,
|
||||
"bottomRow": 3,
|
||||
"parentId": "0",
|
||||
"widgetId": "8n5urob9mz",
|
||||
"dynamicBindingPathList": [],
|
||||
"defaultText": "<note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note>"
|
||||
"id": "Page1",
|
||||
"isDefault": true
|
||||
}
|
||||
]
|
||||
],
|
||||
"publishedPages": [
|
||||
{
|
||||
"id": "Page1",
|
||||
"isDefault": true
|
||||
}
|
||||
],
|
||||
"viewMode": false,
|
||||
"appIsExample": false,
|
||||
"unreadCommentThreads": 0.0,
|
||||
"color": "#EAEDFB",
|
||||
"icon": "yen",
|
||||
"slug": "xml-paser-test",
|
||||
"unpublishedCustomJSLibs": [],
|
||||
"publishedCustomJSLibs": [],
|
||||
"evaluationVersion": 2.0,
|
||||
"applicationVersion": 2.0,
|
||||
"collapseInvisibleWidgets": true,
|
||||
"isManualUpdate": false,
|
||||
"deleted": false
|
||||
},
|
||||
"datasourceList": [],
|
||||
"customJSLibList": [],
|
||||
"pageList": [
|
||||
{
|
||||
"unpublishedPage": {
|
||||
"name": "Page1",
|
||||
"slug": "page1",
|
||||
"layouts": [
|
||||
{
|
||||
"viewMode": false,
|
||||
"dsl": {
|
||||
"widgetName": "MainContainer",
|
||||
"backgroundColor": "none",
|
||||
"rightColumn": 4896.0,
|
||||
"snapColumns": 64.0,
|
||||
"detachFromLayout": true,
|
||||
"widgetId": "0",
|
||||
"topRow": 0.0,
|
||||
"bottomRow": 380.0,
|
||||
"containerStyle": "none",
|
||||
"snapRows": 124.0,
|
||||
"parentRowSpace": 1.0,
|
||||
"type": "CANVAS_WIDGET",
|
||||
"canExtend": true,
|
||||
"version": 87.0,
|
||||
"minHeight": 1292.0,
|
||||
"dynamicTriggerPathList": [],
|
||||
"parentColumnSpace": 1.0,
|
||||
"dynamicBindingPathList": [],
|
||||
"leftColumn": 0.0,
|
||||
"children": [
|
||||
{
|
||||
"mobileBottomRow": 14.0,
|
||||
"widgetName": "Text1",
|
||||
"displayName": "Text",
|
||||
"iconSVG": "https://release-appcdn.appsmith.com/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg",
|
||||
"searchTags": [
|
||||
"typography",
|
||||
"paragraph",
|
||||
"label"
|
||||
],
|
||||
"topRow": 0.0,
|
||||
"bottomRow": 16.0,
|
||||
"parentRowSpace": 10.0,
|
||||
"type": "TEXT_WIDGET",
|
||||
"hideCard": false,
|
||||
"mobileRightColumn": 23.0,
|
||||
"animateLoading": true,
|
||||
"overflow": "NONE",
|
||||
"fontFamily": "{{appsmith.theme.fontFamily.appFont}}",
|
||||
"parentColumnSpace": 14.953125,
|
||||
"dynamicTriggerPathList": [],
|
||||
"leftColumn": 0.0,
|
||||
"dynamicBindingPathList": [
|
||||
{
|
||||
"key": "truncateButtonColor"
|
||||
},
|
||||
{
|
||||
"key": "fontFamily"
|
||||
},
|
||||
{
|
||||
"key": "borderRadius"
|
||||
},
|
||||
{
|
||||
"key": "text"
|
||||
}
|
||||
],
|
||||
"shouldTruncate": false,
|
||||
"truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||
"text": "{{xmlParser.parse(Input1.text)}}",
|
||||
"key": "bdg0tfrf6x",
|
||||
"isDeprecated": false,
|
||||
"rightColumn": 13.0,
|
||||
"textAlign": "LEFT",
|
||||
"dynamicHeight": "AUTO_HEIGHT",
|
||||
"widgetId": "b8blvt9b2z",
|
||||
"minWidth": 450.0,
|
||||
"isVisible": true,
|
||||
"fontStyle": "BOLD",
|
||||
"textColor": "#231F20",
|
||||
"version": 1.0,
|
||||
"parentId": "0",
|
||||
"tags": [
|
||||
"Suggested",
|
||||
"Content"
|
||||
],
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"mobileTopRow": 10.0,
|
||||
"responsiveBehavior": "fill",
|
||||
"originalTopRow": 0.0,
|
||||
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||
"mobileLeftColumn": 7.0,
|
||||
"maxDynamicHeight": 9000.0,
|
||||
"originalBottomRow": 4.0,
|
||||
"fontSize": "1rem",
|
||||
"minDynamicHeight": 4.0
|
||||
},
|
||||
{
|
||||
"boxShadow": "none",
|
||||
"iconSVG": "https://release-appcdn.appsmith.com/static/media/icon.f2c34197dbcf03595098986de898928f.svg",
|
||||
"topRow": 17.0,
|
||||
"labelWidth": 5.0,
|
||||
"type": "INPUT_WIDGET_V2",
|
||||
"animateLoading": true,
|
||||
"resetOnSubmit": true,
|
||||
"leftColumn": 0.0,
|
||||
"dynamicBindingPathList": [
|
||||
{
|
||||
"key": "accentColor"
|
||||
},
|
||||
{
|
||||
"key": "borderRadius"
|
||||
}
|
||||
],
|
||||
"labelStyle": "",
|
||||
"inputType": "TEXT",
|
||||
"isDisabled": false,
|
||||
"isRequired": false,
|
||||
"dynamicHeight": "FIXED",
|
||||
"accentColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||
"showStepArrows": false,
|
||||
"isVisible": true,
|
||||
"version": 2.0,
|
||||
"tags": [
|
||||
"Suggested",
|
||||
"Inputs"
|
||||
],
|
||||
"isLoading": false,
|
||||
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||
"originalBottomRow": 21.0,
|
||||
"mobileBottomRow": 21.0,
|
||||
"widgetName": "Input1",
|
||||
"displayName": "Input",
|
||||
"searchTags": [
|
||||
"form",
|
||||
"text input",
|
||||
"number",
|
||||
"textarea"
|
||||
],
|
||||
"bottomRow": 24.0,
|
||||
"parentRowSpace": 10.0,
|
||||
"autoFocus": false,
|
||||
"hideCard": false,
|
||||
"mobileRightColumn": 19.0,
|
||||
"parentColumnSpace": 14.34375,
|
||||
"dynamicTriggerPathList": [],
|
||||
"labelPosition": "Top",
|
||||
"key": "mx0emg6xlv",
|
||||
"labelTextSize": "0.875rem",
|
||||
"isDeprecated": false,
|
||||
"rightColumn": 19.0,
|
||||
"widgetId": "ni16fc0xys",
|
||||
"minWidth": 450.0,
|
||||
"label": "Label",
|
||||
"parentId": "0",
|
||||
"labelAlignment": "left",
|
||||
"renderMode": "CANVAS",
|
||||
"mobileTopRow": 14.0,
|
||||
"responsiveBehavior": "fill",
|
||||
"originalTopRow": 14.0,
|
||||
"mobileLeftColumn": 0.0,
|
||||
"maxDynamicHeight": 9000.0,
|
||||
"iconAlign": "left",
|
||||
"defaultText": "<note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> </note>",
|
||||
"minDynamicHeight": 4.0
|
||||
},
|
||||
{
|
||||
"mobileBottomRow": 35.0,
|
||||
"widgetName": "Text2",
|
||||
"displayName": "Text",
|
||||
"iconSVG": "https://release-appcdn.appsmith.com/static/media/icon.a47d6d5dbbb718c4dc4b2eb4f218c1b7.svg",
|
||||
"searchTags": [
|
||||
"typography",
|
||||
"paragraph",
|
||||
"label"
|
||||
],
|
||||
"topRow": 31.0,
|
||||
"bottomRow": 35.0,
|
||||
"parentRowSpace": 10.0,
|
||||
"type": "TEXT_WIDGET",
|
||||
"hideCard": false,
|
||||
"mobileRightColumn": 16.0,
|
||||
"animateLoading": true,
|
||||
"overflow": "NONE",
|
||||
"fontFamily": "{{appsmith.theme.fontFamily.appFont}}",
|
||||
"parentColumnSpace": 14.34375,
|
||||
"leftColumn": 0.0,
|
||||
"dynamicBindingPathList": [
|
||||
{
|
||||
"key": "truncateButtonColor"
|
||||
},
|
||||
{
|
||||
"key": "fontFamily"
|
||||
},
|
||||
{
|
||||
"key": "borderRadius"
|
||||
},
|
||||
{
|
||||
"key": "text"
|
||||
}
|
||||
],
|
||||
"shouldTruncate": false,
|
||||
"truncateButtonColor": "{{appsmith.theme.colors.primaryColor}}",
|
||||
"text": "Hello {{appsmith.user.name || appsmith.user.email}}",
|
||||
"key": "bdg0tfrf6x",
|
||||
"isDeprecated": false,
|
||||
"rightColumn": 20.0,
|
||||
"textAlign": "LEFT",
|
||||
"dynamicHeight": "AUTO_HEIGHT",
|
||||
"widgetId": "3m7c3st35v",
|
||||
"minWidth": 450.0,
|
||||
"isVisible": true,
|
||||
"fontStyle": "BOLD",
|
||||
"textColor": "#231F20",
|
||||
"version": 1.0,
|
||||
"parentId": "0",
|
||||
"tags": [
|
||||
"Suggested",
|
||||
"Content"
|
||||
],
|
||||
"renderMode": "CANVAS",
|
||||
"isLoading": false,
|
||||
"mobileTopRow": 31.0,
|
||||
"responsiveBehavior": "fill",
|
||||
"borderRadius": "{{appsmith.theme.borderRadius.appBorderRadius}}",
|
||||
"mobileLeftColumn": 0.0,
|
||||
"maxDynamicHeight": 9000.0,
|
||||
"fontSize": "1rem",
|
||||
"minDynamicHeight": 4.0
|
||||
}
|
||||
]
|
||||
},
|
||||
"layoutOnLoadActions": [],
|
||||
"layoutOnLoadActionErrors": [],
|
||||
"validOnPageLoadActions": true,
|
||||
"id": "Page1",
|
||||
"deleted": false,
|
||||
"policies": [],
|
||||
"userPermissions": []
|
||||
}
|
||||
],
|
||||
"userPermissions": [],
|
||||
"policies": []
|
||||
},
|
||||
"publishedPage": {
|
||||
"name": "Page1",
|
||||
"slug": "page1",
|
||||
"layouts": [
|
||||
{
|
||||
"viewMode": false,
|
||||
"dsl": {
|
||||
"widgetName": "MainContainer",
|
||||
"backgroundColor": "none",
|
||||
"rightColumn": 1224.0,
|
||||
"snapColumns": 16.0,
|
||||
"detachFromLayout": true,
|
||||
"widgetId": "0",
|
||||
"topRow": 0.0,
|
||||
"bottomRow": 1250.0,
|
||||
"containerStyle": "none",
|
||||
"snapRows": 33.0,
|
||||
"parentRowSpace": 1.0,
|
||||
"type": "CANVAS_WIDGET",
|
||||
"canExtend": true,
|
||||
"version": 4.0,
|
||||
"minHeight": 1292.0,
|
||||
"dynamicTriggerPathList": [],
|
||||
"parentColumnSpace": 1.0,
|
||||
"dynamicBindingPathList": [],
|
||||
"leftColumn": 0.0,
|
||||
"children": []
|
||||
},
|
||||
"validOnPageLoadActions": true,
|
||||
"id": "Page1",
|
||||
"deleted": false,
|
||||
"policies": [],
|
||||
"userPermissions": []
|
||||
}
|
||||
],
|
||||
"userPermissions": [],
|
||||
"policies": []
|
||||
},
|
||||
"deleted": false,
|
||||
"gitSyncId": "6529174c97a7581320fb6a4f_6529174c97a7581320fb6a51"
|
||||
}
|
||||
],
|
||||
"actionList": [],
|
||||
"actionCollectionList": [],
|
||||
"updatedResources": {
|
||||
"customJSLibList": [],
|
||||
"actionList": [],
|
||||
"pageList": [
|
||||
"Page1"
|
||||
],
|
||||
"actionCollectionList": []
|
||||
},
|
||||
"editModeTheme": {
|
||||
"name": "Default-New",
|
||||
"displayName": "Modern",
|
||||
"isSystemTheme": true,
|
||||
"deleted": false
|
||||
},
|
||||
"publishedTheme": {
|
||||
"name": "Default-New",
|
||||
"displayName": "Modern",
|
||||
"isSystemTheme": true,
|
||||
"deleted": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -104,7 +104,6 @@
|
|||
"echarts-gl": "^2.0.9",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-sort": "^3.4.0",
|
||||
"fast-xml-parser": "^3.17.5",
|
||||
"fastdom": "^1.0.11",
|
||||
"focus-trap-react": "^8.9.2",
|
||||
"fuse.js": "^3.4.5",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
|
||||
export function fetchJSLibraries(applicationId: string) {
|
||||
return {
|
||||
|
|
@ -8,7 +8,7 @@ export function fetchJSLibraries(applicationId: string) {
|
|||
};
|
||||
}
|
||||
|
||||
export function installLibraryInit(payload: Partial<TJSLibrary>) {
|
||||
export function installLibraryInit(payload: Partial<JSLibrary>) {
|
||||
return {
|
||||
type: ReduxActionTypes.INSTALL_LIBRARY_INIT,
|
||||
payload,
|
||||
|
|
@ -22,7 +22,7 @@ export function toggleInstaller(payload: boolean) {
|
|||
};
|
||||
}
|
||||
|
||||
export function uninstallLibraryInit(payload: TJSLibrary) {
|
||||
export function uninstallLibraryInit(payload: JSLibrary) {
|
||||
return {
|
||||
type: ReduxActionTypes.UNINSTALL_LIBRARY_INIT,
|
||||
payload,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { APP_MODE } from "entities/App";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import Api from "./Api";
|
||||
|
||||
export default class LibraryApi extends Api {
|
||||
|
|
@ -10,7 +10,7 @@ export default class LibraryApi extends Api {
|
|||
|
||||
static async addLibrary(
|
||||
applicationId: string,
|
||||
library: Partial<TJSLibrary> & { defs: string },
|
||||
library: Partial<JSLibrary> & { defs: string },
|
||||
) {
|
||||
const url = LibraryApi.getUpdateLibraryBaseURL(applicationId) + "/add";
|
||||
return Api.patch(url, library);
|
||||
|
|
@ -18,7 +18,7 @@ export default class LibraryApi extends Api {
|
|||
|
||||
static async removeLibrary(
|
||||
applicationId: string,
|
||||
library: Partial<TJSLibrary>,
|
||||
library: Partial<JSLibrary>,
|
||||
) {
|
||||
const url = LibraryApi.getUpdateLibraryBaseURL(applicationId) + "/remove";
|
||||
return Api.patch(url, library);
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ import {
|
|||
|
||||
import { InstallState } from "reducers/uiReducers/libraryReducer";
|
||||
import recommendedLibraries from "pages/Editor/Explorer/Libraries/recommendedLibraries";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import { getEntityNameAndPropertyPath } from "@appsmith/workers/Evaluation/evaluationUtils";
|
||||
import { getFormValues } from "redux-form";
|
||||
import { TEMP_DATASOURCE_ID } from "constants/Datasource";
|
||||
|
|
@ -1099,7 +1099,7 @@ export const selectLibrariesForExplorer = createSelector(
|
|||
version: recommendedLibrary?.version || "",
|
||||
url: recommendedLibrary?.url || url,
|
||||
accessor: [],
|
||||
} as TJSLibrary;
|
||||
} as JSLibrary;
|
||||
});
|
||||
return [...queuedInstalls, ...libs];
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
{
|
||||
"!name": "LIB/xmlParser",
|
||||
"xmlParser": {
|
||||
"parse": {
|
||||
"!doc": "converts xml string to json object",
|
||||
"!type": "fn(xml: string, options?: object, validationOption?: object) -> object"
|
||||
},
|
||||
"validate": {
|
||||
"!doc": "validate xml data",
|
||||
"!type": "fn(xml: string) -> bool"
|
||||
},
|
||||
"convertToJson": {
|
||||
"!type": "fn(node: ?, options: object) -> ?"
|
||||
},
|
||||
"convertToJsonString": {
|
||||
"!type": "fn(node: ?, options: object) -> string"
|
||||
},
|
||||
"convertTonimn": {
|
||||
"!type": "fn(node: ?, e_schema: ?, options: object) -> ?"
|
||||
},
|
||||
"getTraversalObj": {
|
||||
"!type": "fn(xmlData: ?, options: object) -> ?"
|
||||
},
|
||||
"j2xParser": {
|
||||
"!type": "fn(options: object) -> object",
|
||||
"prototype": {
|
||||
"parse": {
|
||||
"!type": "fn(jObj: ?)"
|
||||
},
|
||||
"j2x": {
|
||||
"!type": "fn(jObj: ?, level: ?)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"parseToNimn": {
|
||||
"!type": "fn(xmlData: ?, schema: ?, options: ?) -> ?"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,7 +36,7 @@ import recommendedLibraries from "pages/Editor/Explorer/Libraries/recommendedLib
|
|||
import type { AppState } from "@appsmith/reducers";
|
||||
import { installLibraryInit } from "actions/JSLibraryActions";
|
||||
import classNames from "classnames";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import { EntityClassNames } from "pages/Editor/Explorer/Entity";
|
||||
|
||||
|
|
@ -317,7 +317,7 @@ export function Installer() {
|
|||
}, [URL, isValid]);
|
||||
|
||||
const installLibrary = useCallback(
|
||||
(lib?: Partial<TJSLibrary>) => {
|
||||
(lib?: Partial<JSLibrary>) => {
|
||||
const url = lib?.url || URL;
|
||||
const isQueued = queuedLibraries.find((libURL) => libURL === url);
|
||||
if (isQueued) return;
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ import {
|
|||
uninstallLibraryInit,
|
||||
} from "actions/JSLibraryActions";
|
||||
import EntityAddButton from "../Entity/AddButton";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import {
|
||||
getCurrentPageId,
|
||||
getPagePermissions,
|
||||
|
|
@ -177,7 +177,7 @@ const Version = styled.div<{ version?: string }>`
|
|||
margin: ${(props) => (props.version ? "0 8px" : "0")};
|
||||
`;
|
||||
|
||||
const PrimaryCTA = function ({ lib }: { lib: TJSLibrary }) {
|
||||
const PrimaryCTA = function ({ lib }: { lib: JSLibrary }) {
|
||||
const installationStatus = useSelector(selectInstallationStatus);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ const PrimaryCTA = function ({ lib }: { lib: TJSLibrary }) {
|
|||
return null;
|
||||
};
|
||||
|
||||
function LibraryEntity({ lib }: { lib: TJSLibrary }) {
|
||||
function LibraryEntity({ lib }: { lib: JSLibrary }) {
|
||||
const openDocs = useCallback(
|
||||
(url?: string) => (e: React.MouseEvent) => {
|
||||
e?.stopPropagation();
|
||||
|
|
|
|||
|
|
@ -5,9 +5,19 @@ export default [
|
|||
author: "auth0",
|
||||
docsURL: "https://github.com/auth0/node-jsonwebtoken#readme",
|
||||
version: "8.5.1",
|
||||
url: `/libraries/jsonwebtoken@8.5.1.js`,
|
||||
url: "/libraries/jsonwebtoken@8.5.1.js",
|
||||
icon: "https://github.com/auth0.png?s=20",
|
||||
},
|
||||
{
|
||||
name: "fast-xml-parser",
|
||||
description:
|
||||
"Validate XML, Parse XML to JS Object, or Build XML from JS Object without C/C++ based libraries and no callback.",
|
||||
author: "NaturalIntelligence",
|
||||
docsURL: "https://github.com/NaturalIntelligence/fast-xml-parser",
|
||||
url: "https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/4.3.2/fxparser.min.js",
|
||||
version: "4.3.2",
|
||||
icon: "https://img.jsdelivr.com/github.com/NaturalIntelligence.png",
|
||||
},
|
||||
{
|
||||
name: "jspdf",
|
||||
description: "PDF Document creation from JavaScript",
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type {
|
|||
} from "workers/Evaluation/evaluate";
|
||||
import type { DependencyMap } from "utils/DynamicBindingUtils";
|
||||
import type { TJSPropertiesState } from "workers/Evaluation/JSObject/jsPropertiesState";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
|
||||
export enum LINT_WORKER_ACTIONS {
|
||||
LINT_TREE = "LINT_TREE",
|
||||
|
|
@ -78,5 +78,5 @@ export interface getLintErrorsFromTreeResponse {
|
|||
|
||||
export interface updateJSLibraryProps {
|
||||
add?: boolean;
|
||||
libs: TJSLibrary[];
|
||||
libs: JSLibrary[];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
ReduxActionTypes,
|
||||
} from "@appsmith/constants/ReduxActionConstants";
|
||||
import recommendedLibraries from "pages/Editor/Explorer/Libraries/recommendedLibraries";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import { defaultLibraries } from "workers/common/JSLibrary";
|
||||
|
||||
export enum InstallState {
|
||||
|
|
@ -17,14 +17,14 @@ export enum InstallState {
|
|||
|
||||
export interface LibraryState {
|
||||
installationStatus: Record<string, InstallState>;
|
||||
installedLibraries: TJSLibrary[];
|
||||
installedLibraries: JSLibrary[];
|
||||
isInstallerOpen: boolean;
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
isInstallerOpen: false,
|
||||
installationStatus: {},
|
||||
installedLibraries: defaultLibraries.map((lib: TJSLibrary) => {
|
||||
installedLibraries: defaultLibraries.map((lib: JSLibrary) => {
|
||||
return {
|
||||
name: lib.name,
|
||||
docsURL: lib.docsURL,
|
||||
|
|
@ -38,7 +38,7 @@ const initialState = {
|
|||
const jsLibraryReducer = createImmerReducer(initialState, {
|
||||
[ReduxActionTypes.INSTALL_LIBRARY_INIT]: (
|
||||
state: LibraryState,
|
||||
action: ReduxAction<Partial<TJSLibrary>>,
|
||||
action: ReduxAction<Partial<JSLibrary>>,
|
||||
) => {
|
||||
const { url } = action.payload;
|
||||
state.installationStatus[url as string] =
|
||||
|
|
@ -91,7 +91,7 @@ const jsLibraryReducer = createImmerReducer(initialState, {
|
|||
},
|
||||
[ReduxActionTypes.FETCH_JS_LIBRARIES_SUCCESS]: (
|
||||
state: LibraryState,
|
||||
action: ReduxAction<TJSLibrary[]>,
|
||||
action: ReduxAction<JSLibrary[]>,
|
||||
) => {
|
||||
state.installedLibraries = action.payload.concat(
|
||||
initialState.installedLibraries,
|
||||
|
|
@ -99,7 +99,7 @@ const jsLibraryReducer = createImmerReducer(initialState, {
|
|||
},
|
||||
[ReduxActionTypes.UNINSTALL_LIBRARY_SUCCESS]: (
|
||||
state: LibraryState,
|
||||
action: ReduxAction<TJSLibrary>,
|
||||
action: ReduxAction<JSLibrary>,
|
||||
) => {
|
||||
const uLib = action.payload;
|
||||
state.installedLibraries = state.installedLibraries.filter(
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import log from "loglevel";
|
|||
import { APP_MODE } from "entities/App";
|
||||
import { getAppMode } from "@appsmith/selectors/applicationSelectors";
|
||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import { getUsedActionNames } from "selectors/actionSelectors";
|
||||
import AppsmithConsole from "utils/AppsmithConsole";
|
||||
import { selectInstalledLibraries } from "@appsmith/selectors/entitiesSelector";
|
||||
|
|
@ -73,7 +73,7 @@ function* handleInstallationFailure(
|
|||
log.error(message);
|
||||
}
|
||||
|
||||
export function* installLibrarySaga(lib: Partial<TJSLibrary>) {
|
||||
export function* installLibrarySaga(lib: Partial<JSLibrary>) {
|
||||
const { url } = lib;
|
||||
|
||||
const takenNamesMap: Record<string, true> = yield select(
|
||||
|
|
@ -81,7 +81,7 @@ export function* installLibrarySaga(lib: Partial<TJSLibrary>) {
|
|||
"",
|
||||
);
|
||||
|
||||
const installedLibraries: TJSLibrary[] = yield select(
|
||||
const installedLibraries: JSLibrary[] = yield select(
|
||||
selectInstalledLibraries,
|
||||
);
|
||||
|
||||
|
|
@ -232,7 +232,7 @@ export function* installLibrarySaga(lib: Partial<TJSLibrary>) {
|
|||
});
|
||||
}
|
||||
|
||||
function* uninstallLibrarySaga(action: ReduxAction<TJSLibrary>) {
|
||||
function* uninstallLibrarySaga(action: ReduxAction<JSLibrary>) {
|
||||
const { accessor, name } = action.payload;
|
||||
const applicationId: string = yield select(getCurrentApplicationId);
|
||||
|
||||
|
|
@ -320,7 +320,7 @@ function* fetchJSLibraries(action: ReduxAction<string>) {
|
|||
const isValidResponse: boolean = yield validateResponse(response);
|
||||
if (!isValidResponse) return;
|
||||
|
||||
const libraries = response.data as Array<TJSLibrary & { defs: string }>;
|
||||
const libraries = response.data as Array<JSLibrary & { defs: string }>;
|
||||
|
||||
const { message, success }: { success: boolean; message: string } =
|
||||
yield call(
|
||||
|
|
@ -404,7 +404,7 @@ function* startInstallationRequestChannel() {
|
|||
ReduxActionTypes.INSTALL_LIBRARY_INIT,
|
||||
]);
|
||||
while (true) {
|
||||
const action: ReduxAction<Partial<TJSLibrary>> =
|
||||
const action: ReduxAction<Partial<JSLibrary>> =
|
||||
yield take(queueInstallChannel);
|
||||
yield put({
|
||||
type: ReduxActionTypes.INSTALL_LIBRARY_START,
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
|||
import { APP_MODE } from "entities/App";
|
||||
import { call, put, select, takeEvery } from "redux-saga/effects";
|
||||
import { getAppMode } from "@appsmith/selectors/entitiesSelector";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import { logLatestLintPropertyErrors } from "./PostLintingSagas";
|
||||
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||
import type { AppState } from "@appsmith/reducers";
|
||||
|
|
@ -29,7 +29,7 @@ const APPSMITH_CONFIGS = getAppsmithConfigs();
|
|||
export const lintWorker = new Linter();
|
||||
|
||||
function* updateLintGlobals(
|
||||
action: ReduxAction<{ add?: boolean; libs: TJSLibrary[] }>,
|
||||
action: ReduxAction<{ add?: boolean; libs: JSLibrary[] }>,
|
||||
) {
|
||||
const appMode: APP_MODE = yield select(getAppMode);
|
||||
const isEditorMode = appMode === APP_MODE.EDIT;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { DataTree } from "entities/DataTree/dataTreeTypes";
|
|||
import { createSelector } from "reselect";
|
||||
import WidgetFactory from "WidgetProvider/factory";
|
||||
import type { FlattenedWidgetProps } from "WidgetProvider/constants";
|
||||
import type { TJSLibrary } from "workers/common/JSLibrary";
|
||||
import type { JSLibrary } from "workers/common/JSLibrary";
|
||||
import { getDataTree } from "./dataTreeSelectors";
|
||||
import {
|
||||
getExistingPageNames,
|
||||
|
|
@ -28,7 +28,7 @@ export const getUsedActionNames = createSelector(
|
|||
pageNames: Record<string, any>,
|
||||
dataTree: DataTree,
|
||||
parentWidget: FlattenedWidgetProps | undefined,
|
||||
installedLibraries: TJSLibrary[],
|
||||
installedLibraries: JSLibrary[],
|
||||
) => {
|
||||
const map: Record<string, boolean> = {};
|
||||
// The logic has been copied from Explorer/Entity/Name.tsx Component.
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ import * as mod from "../../../common/JSLibrary/ternDefinitionGenerator";
|
|||
|
||||
jest.mock("../../../common/JSLibrary/ternDefinitionGenerator");
|
||||
|
||||
declare const self: WorkerGlobalScope;
|
||||
|
||||
describe("Tests to assert install/uninstall flows", function () {
|
||||
beforeAll(() => {
|
||||
self.importScripts = jest.fn(() => {
|
||||
//@ts-expect-error importScripts is not defined in the test environment
|
||||
self.lodash = {};
|
||||
});
|
||||
|
||||
//@ts-expect-error importScripts is not defined in the test environment
|
||||
self.import = jest.fn();
|
||||
|
||||
const mockTernDefsGenerator = jest.fn(() => ({}));
|
||||
|
|
@ -49,7 +49,7 @@ describe("Tests to assert install/uninstall flows", function () {
|
|||
});
|
||||
});
|
||||
|
||||
it("Reinstalling a different version of the same installed library should fail", async function () {
|
||||
it("Reinstalling a different version of the same installed library should create a new accessor", async function () {
|
||||
const res = await installLibrary({
|
||||
data: {
|
||||
url: "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.0/lodash.min.js",
|
||||
|
|
@ -59,39 +59,43 @@ describe("Tests to assert install/uninstall flows", function () {
|
|||
method: EVAL_WORKER_ASYNC_ACTION.INSTALL_LIBRARY,
|
||||
});
|
||||
expect(res).toEqual({
|
||||
success: false,
|
||||
defs: {},
|
||||
error: expect.any(Error),
|
||||
success: true,
|
||||
defs: {
|
||||
"!name": "LIB/lodash_1",
|
||||
lodash_1: undefined,
|
||||
},
|
||||
accessor: ["lodash_1"],
|
||||
});
|
||||
});
|
||||
|
||||
it("Detects name space collision where there is another entity(api, widget or query) with the same name", async function () {
|
||||
//@ts-expect-error ignore
|
||||
delete self.lodash;
|
||||
it("Detects name space collision where there is another entity(api, widget or query) with the same name and creates a unique accessor", async function () {
|
||||
delete self["lodash"];
|
||||
const res = await installLibrary({
|
||||
data: {
|
||||
url: "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.0/lodash.min.js",
|
||||
takenAccessors: [],
|
||||
takenAccessors: ["lodash_1"],
|
||||
takenNamesMap: { lodash: true },
|
||||
},
|
||||
method: EVAL_WORKER_ASYNC_ACTION.INSTALL_LIBRARY,
|
||||
});
|
||||
expect(res).toEqual({
|
||||
success: false,
|
||||
defs: {},
|
||||
error: expect.any(Error),
|
||||
success: true,
|
||||
defs: {
|
||||
"!name": "LIB/lodash_2",
|
||||
lodash_2: undefined,
|
||||
},
|
||||
accessor: ["lodash_2"],
|
||||
});
|
||||
delete self["lodash_2"];
|
||||
});
|
||||
|
||||
it("Removes or set the accessors to undefined on the global object on uninstallation", async function () {
|
||||
//@ts-expect-error ignore
|
||||
it("Removes or set the accessors to undefined on the global object on un-installation", async function () {
|
||||
self.lodash = {};
|
||||
const res = await uninstallLibrary({
|
||||
data: ["lodash"],
|
||||
method: EVAL_WORKER_SYNC_ACTION.UNINSTALL_LIBRARY,
|
||||
});
|
||||
expect(res).toEqual({ success: true });
|
||||
//@ts-expect-error ignore
|
||||
expect(self.lodash).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -9,10 +9,20 @@ import {
|
|||
JSLibraries,
|
||||
libraryReservedIdentifiers,
|
||||
} from "../../common/JSLibrary";
|
||||
import type { JSLibrary } from "../../common/JSLibrary";
|
||||
import { resetJSLibraries } from "../../common/JSLibrary/resetJSLibraries";
|
||||
import { makeTernDefs } from "../../common/JSLibrary/ternDefinitionGenerator";
|
||||
import type { EvalWorkerASyncRequest, EvalWorkerSyncRequest } from "../types";
|
||||
import { dataTreeEvaluator } from "./evalTree";
|
||||
import log from "loglevel";
|
||||
|
||||
declare global {
|
||||
interface WorkerGlobalScope {
|
||||
[x: string]: any;
|
||||
}
|
||||
}
|
||||
|
||||
declare const self: WorkerGlobalScope;
|
||||
|
||||
enum LibraryInstallError {
|
||||
NameCollisionError,
|
||||
|
|
@ -21,16 +31,6 @@ enum LibraryInstallError {
|
|||
LibraryOverrideError,
|
||||
}
|
||||
|
||||
class NameCollisionError extends Error {
|
||||
code = LibraryInstallError.NameCollisionError;
|
||||
constructor(accessors: string) {
|
||||
super(
|
||||
createMessage(customJSLibraryMessages.NAME_COLLISION_ERROR, accessors),
|
||||
);
|
||||
this.name = "NameCollisionError";
|
||||
}
|
||||
}
|
||||
|
||||
class ImportError extends Error {
|
||||
code = LibraryInstallError.ImportError;
|
||||
constructor(url: string) {
|
||||
|
|
@ -47,25 +47,13 @@ class TernDefinitionError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
class LibraryOverrideError extends Error {
|
||||
code = LibraryInstallError.LibraryOverrideError;
|
||||
data: any;
|
||||
constructor(name: string, data: any) {
|
||||
super(createMessage(customJSLibraryMessages.LIB_OVERRIDE_ERROR, name));
|
||||
this.name = "LibraryOverrideError";
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
const removeDataTreeFromContext = () => {
|
||||
if (!dataTreeEvaluator) return {};
|
||||
const evalTree = dataTreeEvaluator?.getEvalTree();
|
||||
const dataTreeEntityNames = Object.keys(evalTree);
|
||||
const tempDataTreeStore: Record<string, any> = {};
|
||||
for (const entityName of dataTreeEntityNames) {
|
||||
// @ts-expect-error: self is a global variable
|
||||
tempDataTreeStore[entityName] = self[entityName];
|
||||
// @ts-expect-error: self is a global variable
|
||||
delete self[entityName];
|
||||
}
|
||||
return tempDataTreeStore;
|
||||
|
|
@ -76,12 +64,17 @@ function addTempStoredDataTreeToContext(
|
|||
) {
|
||||
const dataTreeEntityNames = Object.keys(tempDataTreeStore);
|
||||
for (const entityName of dataTreeEntityNames) {
|
||||
// @ts-expect-error: self is a global variable
|
||||
self[entityName] = tempDataTreeStore[entityName];
|
||||
}
|
||||
}
|
||||
|
||||
export async function installLibrary(request: EvalWorkerASyncRequest) {
|
||||
export async function installLibrary(
|
||||
request: EvalWorkerASyncRequest<{
|
||||
url: string;
|
||||
takenNamesMap: Record<string, true>;
|
||||
takenAccessors: Array<string>;
|
||||
}>,
|
||||
) {
|
||||
const { data } = request;
|
||||
const { takenAccessors, takenNamesMap, url } = data;
|
||||
const defs: Def = {};
|
||||
|
|
@ -91,73 +84,105 @@ export async function installLibrary(request: EvalWorkerASyncRequest) {
|
|||
* We store the data tree in a temporary variable and add it back to the global scope after the library is imported.
|
||||
*/
|
||||
const tempDataTreeStore = removeDataTreeFromContext();
|
||||
|
||||
// Map of all the currently installed libraries
|
||||
const libStore = takenAccessors.reduce(
|
||||
(acc: Record<string, unknown>, a: string) => {
|
||||
acc[a] = self[a];
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
try {
|
||||
const currentEnvKeys = Object.keys(self);
|
||||
const envKeysBeforeInstallation = Object.keys(self);
|
||||
|
||||
//@ts-expect-error Find libraries that were uninstalled.
|
||||
const unsetKeys = currentEnvKeys.filter((key) => self[key] === undefined);
|
||||
/** Holds keys of uninstalled libraries that cannot be removed from worker global.
|
||||
* Certain libraries are added to the global scope with { configurable: false }
|
||||
*/
|
||||
const unsetLibraryKeys = envKeysBeforeInstallation.filter(
|
||||
(k) => self[k] === undefined,
|
||||
);
|
||||
|
||||
const accessors: string[] = [];
|
||||
|
||||
const existingLibraries: Record<string, any> = {};
|
||||
for (const acc of takenAccessors) {
|
||||
existingLibraries[acc] = self[acc];
|
||||
}
|
||||
let module = null;
|
||||
try {
|
||||
self.importScripts(url);
|
||||
// Find keys add that were installed to the global scope.
|
||||
const keysAfterInstallation = Object.keys(self);
|
||||
accessors.push(
|
||||
...difference(keysAfterInstallation, envKeysBeforeInstallation),
|
||||
);
|
||||
|
||||
// Check the list of installed library to see if their values have changed.
|
||||
// This is to check if the newly installed library overwrites an already existing
|
||||
accessors.push(
|
||||
...Object.keys(libStore).filter((k) => {
|
||||
return libStore[k] !== self[k];
|
||||
}),
|
||||
);
|
||||
|
||||
accessors.push(...unsetLibraryKeys.filter((k) => self[k] !== undefined));
|
||||
|
||||
for (let i = 0; i < accessors.length; i++) {
|
||||
if (
|
||||
takenNamesMap.hasOwnProperty(accessors[i]) ||
|
||||
takenAccessors.includes(accessors[i])
|
||||
) {
|
||||
const uniqueName = generateUniqueAccessor(
|
||||
accessors[i],
|
||||
takenAccessors,
|
||||
takenNamesMap,
|
||||
);
|
||||
self[uniqueName] = self[accessors[i]];
|
||||
accessors[i] = uniqueName;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
log.debug(e, `importScripts failed for ${url}`);
|
||||
try {
|
||||
module = await import(/* webpackIgnore: true */ url);
|
||||
if (module && typeof module === "object") {
|
||||
const uniqAccessor = generateUniqueAccessor(
|
||||
url,
|
||||
takenAccessors,
|
||||
takenNamesMap,
|
||||
);
|
||||
self[uniqAccessor] = flattenModule(module);
|
||||
accessors.push(uniqAccessor);
|
||||
}
|
||||
} catch (e) {
|
||||
log.debug(e, `dynamic import failed for ${url}`);
|
||||
throw new ImportError(url);
|
||||
}
|
||||
}
|
||||
|
||||
// Find keys add that were installed to the global scope.
|
||||
const accessors = difference(
|
||||
Object.keys(self),
|
||||
currentEnvKeys,
|
||||
) as Array<string>;
|
||||
|
||||
// If no keys were added to the global scope, check if the module is a ESM module.
|
||||
// If no accessors at this point, installation likely failed.
|
||||
if (accessors.length === 0) {
|
||||
if (module && typeof module === "object") {
|
||||
const uniqAccessor = generateUniqueAccessor(
|
||||
url,
|
||||
takenAccessors,
|
||||
takenNamesMap,
|
||||
);
|
||||
// @ts-expect-error no types
|
||||
self[uniqAccessor] = flattenModule(module);
|
||||
accessors.push(uniqAccessor);
|
||||
}
|
||||
throw new Error("Unable to determine a unique accessor");
|
||||
}
|
||||
|
||||
addTempStoredDataTreeToContext(tempDataTreeStore);
|
||||
checkForNameCollision(accessors, takenNamesMap);
|
||||
checkIfUninstalledEarlier(accessors, unsetKeys);
|
||||
checkForOverrides(url, accessors, takenAccessors, existingLibraries);
|
||||
if (accessors.length === 0)
|
||||
return { status: false, defs, accessor: accessors };
|
||||
|
||||
//Reserves accessor names.
|
||||
const name = accessors[accessors.length - 1];
|
||||
|
||||
defs["!name"] = `LIB/${name}`;
|
||||
try {
|
||||
for (const key of accessors) {
|
||||
//@ts-expect-error no types
|
||||
defs[key] = makeTernDefs(self[key]);
|
||||
}
|
||||
} catch (e) {
|
||||
for (const acc of accessors) {
|
||||
//@ts-expect-error no types
|
||||
self[acc] = undefined;
|
||||
}
|
||||
log.debug(e, `ternDefinitions failed for ${url}`);
|
||||
throw new TernDefinitionError(
|
||||
`Failed to generate autocomplete definitions: ${name}`,
|
||||
);
|
||||
}
|
||||
|
||||
// All the existing library and the newly installed one is added to global.
|
||||
Object.keys(libStore).forEach((k) => (self[k] = libStore[k]));
|
||||
|
||||
//Reserve accessor names.
|
||||
for (const acc of accessors) {
|
||||
//we have to update invalidEntityIdentifiers as well
|
||||
|
|
@ -167,21 +192,20 @@ export async function installLibrary(request: EvalWorkerASyncRequest) {
|
|||
|
||||
return { success: true, defs, accessor: accessors };
|
||||
} catch (error) {
|
||||
addTempStoredDataTreeToContext(tempDataTreeStore);
|
||||
takenAccessors.forEach((k) => (self[k] = libStore[k]));
|
||||
return { success: false, defs, error };
|
||||
}
|
||||
}
|
||||
|
||||
export function uninstallLibrary(request: EvalWorkerSyncRequest) {
|
||||
export function uninstallLibrary(
|
||||
request: EvalWorkerSyncRequest<Array<string>>,
|
||||
) {
|
||||
const { data } = request;
|
||||
const accessor = data;
|
||||
try {
|
||||
for (const key of accessor) {
|
||||
try {
|
||||
delete self[key];
|
||||
} catch (e) {
|
||||
//@ts-expect-error ignore
|
||||
self[key] = undefined;
|
||||
}
|
||||
self[key] = undefined;
|
||||
//we have to update invalidEntityIdentifiers as well
|
||||
delete libraryReservedIdentifiers[key];
|
||||
delete invalidEntityIdentifiers[key];
|
||||
|
|
@ -192,39 +216,60 @@ export function uninstallLibrary(request: EvalWorkerSyncRequest) {
|
|||
}
|
||||
}
|
||||
|
||||
export async function loadLibraries(request: EvalWorkerASyncRequest) {
|
||||
export async function loadLibraries(
|
||||
request: EvalWorkerASyncRequest<JSLibrary[]>,
|
||||
) {
|
||||
resetJSLibraries();
|
||||
//Add types
|
||||
const { data: libs } = request;
|
||||
let message = "";
|
||||
const libStore: Record<string, unknown> = {};
|
||||
|
||||
try {
|
||||
for (const lib of libs) {
|
||||
const url = lib.url;
|
||||
const accessor = lib.accessor;
|
||||
const url = lib.url as string;
|
||||
const accessors = lib.accessor;
|
||||
const keysBefore = Object.keys(self);
|
||||
let module = null;
|
||||
try {
|
||||
self.importScripts(url);
|
||||
const keysAfter = Object.keys(self);
|
||||
const defaultAccessors = difference(keysAfter, keysBefore);
|
||||
|
||||
/**
|
||||
* Installing 2 different version of lodash tries to add the same accessor on the self object. Let take version a & b for example.
|
||||
* Installation of version a, will add _ to the self object and can be detected by looking at the differences in the previous step.
|
||||
* Now when version b is installed, differences will be [], since _ already exists in the self object.
|
||||
* We add all the installations to the libStore and see if the reference it points to in the self object changes.
|
||||
* If the references changes it means that it a valid accessor.
|
||||
*/
|
||||
defaultAccessors.push(
|
||||
...Object.keys(libStore).filter((k) => libStore[k] !== self[k]),
|
||||
);
|
||||
|
||||
/** Sort the accessor list from backend and installed accessor list using the same rule to apply all modifications.
|
||||
* This is required only for UMD builds, since we always generate unique names for ESM.
|
||||
*/
|
||||
accessors.sort();
|
||||
defaultAccessors.sort();
|
||||
|
||||
for (let i = 0; i < defaultAccessors.length; i++) {
|
||||
self[accessors[i]] = self[defaultAccessors[i]];
|
||||
libStore[defaultAccessors[i]] = self[defaultAccessors[i]];
|
||||
libraryReservedIdentifiers[accessors[i]] = true;
|
||||
invalidEntityIdentifiers[accessors[i]] = true;
|
||||
}
|
||||
} catch (e) {
|
||||
message = (e as Error).message;
|
||||
try {
|
||||
module = await import(/* webpackIgnore: true */ url);
|
||||
if (!module || typeof module !== "object") throw "Not an ESM module";
|
||||
const key = accessors[0];
|
||||
libStore[key] = module;
|
||||
libraryReservedIdentifiers[key] = true;
|
||||
invalidEntityIdentifiers[key] = true;
|
||||
} catch (e) {
|
||||
message = (e as Error).message;
|
||||
throw new ImportError(url);
|
||||
}
|
||||
}
|
||||
const keysAfter = Object.keys(self);
|
||||
const newKeys = difference(keysAfter, keysBefore);
|
||||
if (newKeys.length === 0 && module && typeof module === "object") {
|
||||
self[accessor[0]] = flattenModule(module);
|
||||
newKeys.push(accessor[0]);
|
||||
}
|
||||
for (const key of newKeys) {
|
||||
//we have to update invalidEntityIdentifiers as well
|
||||
libraryReservedIdentifiers[key] = true;
|
||||
invalidEntityIdentifiers[key] = true;
|
||||
}
|
||||
}
|
||||
JSLibraries.push(...libs);
|
||||
return { success: true, message };
|
||||
|
|
@ -234,48 +279,6 @@ export async function loadLibraries(request: EvalWorkerASyncRequest) {
|
|||
}
|
||||
}
|
||||
|
||||
function checkForNameCollision(
|
||||
accessor: string[],
|
||||
takenNamesMap: Record<string, any>,
|
||||
) {
|
||||
const collidingNames = accessor.filter((key: string) => takenNamesMap[key]);
|
||||
if (collidingNames.length) {
|
||||
for (const acc of accessor) {
|
||||
//@ts-expect-error no types
|
||||
self[acc] = undefined;
|
||||
}
|
||||
throw new NameCollisionError(collidingNames.join(", "));
|
||||
}
|
||||
}
|
||||
|
||||
function checkIfUninstalledEarlier(accessor: string[], unsetKeys: string[]) {
|
||||
if (accessor.length > 0) return;
|
||||
for (const key of unsetKeys) {
|
||||
//@ts-expect-error no types
|
||||
if (!self[key]) continue;
|
||||
accessor.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
function checkForOverrides(
|
||||
url: string,
|
||||
accessor: string[],
|
||||
takenAccessors: string[],
|
||||
existingLibraries: Record<string, any>,
|
||||
) {
|
||||
if (accessor.length > 0) return;
|
||||
const overriddenAccessors: Array<string> = [];
|
||||
for (const acc of takenAccessors) {
|
||||
//@ts-expect-error no types
|
||||
if (existingLibraries[acc] === self[acc]) continue;
|
||||
//@ts-expect-error no types
|
||||
self[acc] = existingLibraries[acc];
|
||||
overriddenAccessors.push(acc);
|
||||
}
|
||||
if (overriddenAccessors.length === 0) return;
|
||||
throw new LibraryOverrideError(url, overriddenAccessors);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called only for ESM modules and generates a unique namespace for the module.
|
||||
* @param url
|
||||
|
|
@ -284,22 +287,24 @@ function checkForOverrides(
|
|||
* @returns
|
||||
*/
|
||||
function generateUniqueAccessor(
|
||||
url: string,
|
||||
urlOrName: string,
|
||||
takenAccessors: Array<string>,
|
||||
takenNamesMap: Record<string, true>,
|
||||
) {
|
||||
let name = urlOrName;
|
||||
// extract file name from url
|
||||
const urlObject = new URL(url);
|
||||
// URL pattern for ESM modules from jsDelivr - https://cdn.jsdelivr.net/npm/stripe@13.3.0/+esm
|
||||
// Assuming the file name is the last part of the path
|
||||
const urlPathParts = urlObject.pathname.split("/");
|
||||
let fileName = urlPathParts.pop();
|
||||
fileName = fileName?.includes("esm") ? urlPathParts.pop() : fileName;
|
||||
try {
|
||||
// Checks to see if a URL was passed
|
||||
const urlObject = new URL(urlOrName);
|
||||
// URL pattern for ESM modules from jsDelivr - https://cdn.jsdelivr.net/npm/stripe@13.3.0/+esm
|
||||
// Assuming the file name is the last part of the path
|
||||
const urlPathParts = urlObject.pathname.split("/");
|
||||
name = urlPathParts.pop() as string;
|
||||
name = name?.includes("+esm") ? (urlPathParts.pop() as string) : name;
|
||||
} catch (e) {}
|
||||
|
||||
// This should never happen. This is just to avoid the typescript error.
|
||||
if (!fileName) throw new Error("Unable to generate a unique accessor");
|
||||
// Replace all non-alphabetic characters with underscores and remove trailing underscores
|
||||
const validVar = fileName.replace(/[^a-zA-Z]/g, "_").replace(/_+$/, "");
|
||||
const validVar = name.replace(/[^a-zA-Z]/g, "_").replace(/_+$/, "");
|
||||
if (
|
||||
!takenAccessors.includes(validVar) &&
|
||||
!takenNamesMap.hasOwnProperty(validVar)
|
||||
|
|
@ -308,7 +313,7 @@ function generateUniqueAccessor(
|
|||
}
|
||||
let index = 0;
|
||||
while (index++ < 100) {
|
||||
const name = `Library_${index}`;
|
||||
const name = `${validVar}_${index}`;
|
||||
if (!takenAccessors.includes(name) && !takenNamesMap.hasOwnProperty(name)) {
|
||||
return name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,9 +19,12 @@ import type { WorkerRequest } from "@appsmith/workers/common/types";
|
|||
import type { DataTreeDiff } from "@appsmith/workers/Evaluation/evaluationUtils";
|
||||
import type { APP_MODE } from "entities/App";
|
||||
|
||||
export type EvalWorkerSyncRequest = WorkerRequest<any, EVAL_WORKER_SYNC_ACTION>;
|
||||
export type EvalWorkerASyncRequest = WorkerRequest<
|
||||
any,
|
||||
export type EvalWorkerSyncRequest<T = any> = WorkerRequest<
|
||||
T,
|
||||
EVAL_WORKER_SYNC_ACTION
|
||||
>;
|
||||
export type EvalWorkerASyncRequest<T = any> = WorkerRequest<
|
||||
T,
|
||||
EVAL_WORKER_ASYNC_ACTION
|
||||
>;
|
||||
export type EvalWorkerResponse = EvalTreeResponseData | boolean | unknown;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import ecma from "constants/defs/ecmascript.json";
|
|||
import lodash from "constants/defs/lodash.json";
|
||||
import base64 from "constants/defs/base64-js.json";
|
||||
import moment from "constants/defs/moment.json";
|
||||
import xmlJs from "constants/defs/xmlParser.json";
|
||||
import forge from "constants/defs/forge.json";
|
||||
import browser from "constants/defs/browser.json";
|
||||
import {
|
||||
|
|
@ -64,7 +63,6 @@ function startServer(plugins = {}, scripts?: string[]) {
|
|||
lodash,
|
||||
base64,
|
||||
moment,
|
||||
xmlJs,
|
||||
forge,
|
||||
] as Def[],
|
||||
plugins: plugins,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import lodashPackageJson from "lodash/package.json";
|
||||
import momentPackageJson from "moment-timezone/package.json";
|
||||
|
||||
export interface TJSLibrary {
|
||||
export interface JSLibrary {
|
||||
version?: string;
|
||||
docsURL: string;
|
||||
name: string;
|
||||
|
|
@ -9,7 +9,7 @@ export interface TJSLibrary {
|
|||
url?: string;
|
||||
}
|
||||
|
||||
export const defaultLibraries: TJSLibrary[] = [
|
||||
export const defaultLibraries: JSLibrary[] = [
|
||||
{
|
||||
accessor: ["_"],
|
||||
version: lodashPackageJson.version,
|
||||
|
|
@ -22,12 +22,6 @@ export const defaultLibraries: TJSLibrary[] = [
|
|||
docsURL: `https://momentjs.com/docs/`,
|
||||
name: "moment",
|
||||
},
|
||||
{
|
||||
accessor: ["xmlParser"],
|
||||
version: "3.17.5",
|
||||
docsURL: "https://github.com/NaturalIntelligence/fast-xml-parser",
|
||||
name: "xmlParser",
|
||||
},
|
||||
{
|
||||
accessor: ["forge"],
|
||||
version: "1.3.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import _ from "./lodash-wrapper";
|
||||
import moment from "moment-timezone";
|
||||
import parser from "fast-xml-parser";
|
||||
import forge from "node-forge";
|
||||
import { defaultLibraries } from "./index";
|
||||
import { JSLibraries, libraryReservedIdentifiers } from "./index";
|
||||
|
|
@ -8,7 +7,6 @@ import { invalidEntityIdentifiers } from "../DependencyMap/utils";
|
|||
const defaultLibImplementations = {
|
||||
lodash: _,
|
||||
moment: moment,
|
||||
xmlParser: parser,
|
||||
// We are removing some functionalities of node-forge because they wont
|
||||
// work in the worker thread
|
||||
forge: /*#__PURE*/ _.omit(forge, ["tls", "http", "xhr", "socket", "task"]),
|
||||
|
|
|
|||
|
|
@ -10511,7 +10511,6 @@ __metadata:
|
|||
factory.ts: ^0.5.1
|
||||
fast-deep-equal: ^3.1.3
|
||||
fast-sort: ^3.4.0
|
||||
fast-xml-parser: ^3.17.5
|
||||
fastdom: ^1.0.11
|
||||
focus-trap-react: ^8.9.2
|
||||
fuse.js: ^3.4.5
|
||||
|
|
@ -16679,15 +16678,6 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fast-xml-parser@npm:^3.17.5":
|
||||
version: 3.17.5
|
||||
resolution: "fast-xml-parser@npm:3.17.5"
|
||||
bin:
|
||||
xml2js: cli.js
|
||||
checksum: 6c436f540a4dcab67d395c0f6e8dc70090e6ced2ff73ed5fec181c1b25df755ed9fd9ba8271d6f70096fbe3add8b4eac130a5f4daeb12970427f72403a56934e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"fastdom@npm:^1.0.11":
|
||||
version: 1.0.11
|
||||
resolution: "fastdom@npm:1.0.11"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,34 @@
|
|||
package com.appsmith.server.constants;
|
||||
|
||||
import com.appsmith.server.domains.CustomJSLib;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
public class ApplicationConstants {
|
||||
public static final String[] APP_CARD_COLORS = {
|
||||
"#FFDEDE", "#FFEFDB", "#F3F1C7", "#F4FFDE", "#C7F3F0", "#D9E7FF", "#E3DEFF", "#F1DEFF", "#C7F3E3", "#F5D1D1",
|
||||
"#ECECEC", "#FBF4ED", "#D6D1F2", "#FFEBFB", "#EAEDFB"
|
||||
};
|
||||
|
||||
public static CustomJSLib getDefaultParserCustomJsLibCompatibilityDTO() {
|
||||
CustomJSLib customJSLib = new CustomJSLib();
|
||||
customJSLib.setName("xmlParser");
|
||||
customJSLib.setVersion("3.17.5");
|
||||
customJSLib.setAccessor(Set.of("xmlParser"));
|
||||
customJSLib.setUrl("https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.17.5/parser.min.js");
|
||||
customJSLib.setDefs(
|
||||
"{\"!name\":\"LIB/xmlParser\",\"xmlParser\":{\"parse\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertTonimn\":{\"!type\":\"fn()\",\"prototype\":{}},\"getTraversalObj\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertToJson\":{\"!type\":\"fn()\",\"prototype\":{}},\"convertToJsonString\":{\"!type\":\"fn()\",\"prototype\":{}},\"validate\":{\"!type\":\"fn()\",\"prototype\":{}},\"j2xParser\":{\"!type\":\"fn()\",\"prototype\":{\"parse\":{\"!type\":\"fn()\",\"prototype\":{}},\"j2x\":{\"!type\":\"fn()\",\"prototype\":{}}}},\"parseToNimn\":{\"!type\":\"fn()\",\"prototype\":{}}}}");
|
||||
customJSLib.setUidString(XML_PARSER_LIBRARY_UID);
|
||||
return customJSLib;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appsmith provides xmlParser v 3.17.5 and few other customJSLibraries by default, xmlParser has been
|
||||
* flagged because it has some vulnerabilities. Appsmith is stopping natively providing support for xmlParser.
|
||||
* This however, would break existing applications which are using xmlParser. In order to prevent this,
|
||||
* we are adding xmlParser as an add-onn to all existing applications and applications which will be imported
|
||||
* This CustomJSLib UID needs to be added to all the imported applications where we don't have any later versions of xmlParser present.
|
||||
*/
|
||||
public static final String XML_PARSER_LIBRARY_UID =
|
||||
"xmlParser_https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/3.17.5/parser.min.js";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.appsmith.external.models.DefaultResources;
|
|||
import com.appsmith.external.models.OAuth2;
|
||||
import com.appsmith.external.models.Policy;
|
||||
import com.appsmith.server.actioncollections.base.ActionCollectionService;
|
||||
import com.appsmith.server.constants.ApplicationConstants;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.constants.ResourceModes;
|
||||
import com.appsmith.server.datasources.base.DatasourceService;
|
||||
|
|
@ -1135,6 +1136,8 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
customJSLibs = new ArrayList<>();
|
||||
}
|
||||
|
||||
ensureXmlParserPresenceInCustomJsLibList(customJSLibs);
|
||||
|
||||
return Flux.fromIterable(customJSLibs)
|
||||
.flatMap(customJSLib -> {
|
||||
customJSLib.setId(null);
|
||||
|
|
@ -1154,6 +1157,32 @@ public class ImportApplicationServiceCEImpl implements ImportApplicationServiceC
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This method takes customJSLibList from application JSON, checks if an entry for XML parser exists,
|
||||
* otherwise adds the entry.
|
||||
* This has been done to add the xmlParser entry in imported application as appsmith is stopping native support
|
||||
* for xml parser.
|
||||
* Read More: https://github.com/appsmithorg/appsmith/pull/28012
|
||||
*
|
||||
* @param customJSLibList
|
||||
*/
|
||||
public void ensureXmlParserPresenceInCustomJsLibList(List<CustomJSLib> customJSLibList) {
|
||||
boolean isXmlParserLibFound = false;
|
||||
for (CustomJSLib customJSLib : customJSLibList) {
|
||||
if (!customJSLib.getUidString().equals(ApplicationConstants.XML_PARSER_LIBRARY_UID)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
isXmlParserLibFound = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isXmlParserLibFound) {
|
||||
CustomJSLib xmlParserJsLib = ApplicationConstants.getDefaultParserCustomJsLibCompatibilityDTO();
|
||||
customJSLibList.add(xmlParserJsLib);
|
||||
}
|
||||
}
|
||||
|
||||
private Mono<List<Datasource>> getExistingDatasourceMono(String applicationId, Flux<Datasource> datasourceFlux) {
|
||||
Mono<List<Datasource>> existingDatasourceMono;
|
||||
// Check if the request is to hydrate the application to DB for particular branch
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.appsmith.server.migrations;
|
|||
import com.appsmith.external.models.ActionDTO;
|
||||
import com.appsmith.external.models.BaseDomain;
|
||||
import com.appsmith.external.models.InvisibleActionFields;
|
||||
import com.appsmith.server.constants.FieldName;
|
||||
import com.appsmith.server.constants.ResourceModes;
|
||||
import com.appsmith.server.domains.ApplicationPage;
|
||||
import com.appsmith.server.domains.NewAction;
|
||||
|
|
@ -236,4 +237,23 @@ public class MigrationHelperMethods {
|
|||
mongoTemplate.find(query(where(fieldName(path)).is(id)), type);
|
||||
return domainObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* The method provides the criteria for any document to qualify as not deleted
|
||||
* @return Criteria
|
||||
*/
|
||||
public static Criteria notDeleted() {
|
||||
return new Criteria()
|
||||
.andOperator(
|
||||
// Older check for deleted
|
||||
new Criteria()
|
||||
.orOperator(
|
||||
where(FieldName.DELETED).exists(false),
|
||||
where(FieldName.DELETED).is(false)),
|
||||
// New check for deleted
|
||||
new Criteria()
|
||||
.orOperator(
|
||||
where(FieldName.DELETED_AT).exists(false),
|
||||
where(FieldName.DELETED_AT).is(null)));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
package com.appsmith.server.migrations.db.ce;
|
||||
|
||||
import com.appsmith.server.constants.ApplicationConstants;
|
||||
import com.appsmith.server.domains.Application;
|
||||
import com.appsmith.server.domains.CustomJSLib;
|
||||
import com.appsmith.server.domains.QApplication;
|
||||
import com.appsmith.server.dtos.CustomJSLibApplicationDTO;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import io.mongock.api.annotations.ChangeUnit;
|
||||
import io.mongock.api.annotations.Execution;
|
||||
import io.mongock.api.annotations.RollbackExecution;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.data.mongodb.core.MongoTemplate;
|
||||
import org.springframework.data.mongodb.core.query.Criteria;
|
||||
import org.springframework.data.mongodb.core.query.Query;
|
||||
import org.springframework.data.mongodb.core.query.Update;
|
||||
|
||||
import static com.appsmith.server.constants.ApplicationConstants.XML_PARSER_LIBRARY_UID;
|
||||
import static com.appsmith.server.migrations.MigrationHelperMethods.notDeleted;
|
||||
import static com.appsmith.server.repositories.ce.BaseAppsmithRepositoryCEImpl.fieldName;
|
||||
|
||||
/**
|
||||
* Appsmith provides xmlParser v 3.17.5 and few other customJSLibraries by default, xmlParser has been
|
||||
* flagged because it has some vulnerabilities. Appsmith is stopping natively providing support for xmlParser.
|
||||
* This however, would break existing applications which are using xmlParser. In order to prevent this,
|
||||
* applications require to have xmlParser as added library.
|
||||
*
|
||||
* This migration takes care of adding a document in customJsLib for xml-parser and adding corresponding entry
|
||||
* in application collection
|
||||
*
|
||||
*/
|
||||
@Slf4j
|
||||
@ChangeUnit(order = "032", id = "add-xml-parser-to-application-jslibs", author = " ")
|
||||
public class Migration032AddingXmlParserToApplicationLibraries {
|
||||
|
||||
private final MongoTemplate mongoTemplate;
|
||||
private static final String UNPUBLISHED_CUSTOM_JS_LIBS =
|
||||
fieldName(QApplication.application.unpublishedCustomJSLibs);
|
||||
private static final String PUBLISHED_CUSTOM_JS_LIBS = fieldName(QApplication.application.publishedCustomJSLibs);
|
||||
|
||||
public Migration032AddingXmlParserToApplicationLibraries(MongoTemplate mongoTemplate) {
|
||||
this.mongoTemplate = mongoTemplate;
|
||||
}
|
||||
|
||||
@RollbackExecution
|
||||
public void rollbackExecution() {}
|
||||
|
||||
@Execution
|
||||
public void addXmlParserEntryToEachApplication() {
|
||||
// add the xml-parser to customJSLib if it's not already present
|
||||
CustomJSLib customJSLib = generateXmlParserJSLibObject();
|
||||
try {
|
||||
mongoTemplate.save(customJSLib);
|
||||
} catch (DuplicateKeyException duplicateKeyException) {
|
||||
log.debug(
|
||||
"Addition of xmlParser object in customJSLib failed, because object with similar UID already exists");
|
||||
} catch (Exception exception) {
|
||||
throw new AppsmithException(
|
||||
AppsmithError.MIGRATION_FAILED,
|
||||
"Migration032AddingXmlParserToApplicationLibraries",
|
||||
exception.getMessage(),
|
||||
"Unable to insert xml parser library in CustomJSLib collection");
|
||||
}
|
||||
|
||||
// add uid entry in all these custom js libs
|
||||
Update pushXmlParserUpdate = new Update()
|
||||
.addToSet(PUBLISHED_CUSTOM_JS_LIBS, getXmlParserCustomJSLibApplicationDTO())
|
||||
.addToSet(UNPUBLISHED_CUSTOM_JS_LIBS, getXmlParserCustomJSLibApplicationDTO());
|
||||
|
||||
log.debug("Going to add Xml Parser uid in all application DTOs");
|
||||
mongoTemplate.updateMulti(
|
||||
new Query().addCriteria(getMigrationCriteria()), pushXmlParserUpdate, Application.class);
|
||||
}
|
||||
|
||||
private CustomJSLibApplicationDTO getXmlParserCustomJSLibApplicationDTO() {
|
||||
CustomJSLibApplicationDTO xmlParserApplicationDTO = new CustomJSLibApplicationDTO();
|
||||
xmlParserApplicationDTO.setUidString(XML_PARSER_LIBRARY_UID);
|
||||
return xmlParserApplicationDTO;
|
||||
}
|
||||
|
||||
private static CustomJSLib generateXmlParserJSLibObject() {
|
||||
return ApplicationConstants.getDefaultParserCustomJsLibCompatibilityDTO();
|
||||
}
|
||||
|
||||
private static Criteria getMigrationCriteria() {
|
||||
return notDeleted();
|
||||
}
|
||||
}
|
||||
|
|
@ -968,7 +968,10 @@ public class ImportApplicationServiceTests {
|
|||
final List<ActionCollection> actionCollectionList = tuple.getT5();
|
||||
final List<CustomJSLib> importedJSLibList = tuple.getT6();
|
||||
|
||||
assertEquals(1, importedJSLibList.size());
|
||||
// although the imported list had only one jsLib entry, the other entry comes from ensuring an xml
|
||||
// parser entry
|
||||
// for backward compatibility
|
||||
assertEquals(2, importedJSLibList.size());
|
||||
CustomJSLib importedJSLib = (CustomJSLib) importedJSLibList.toArray()[0];
|
||||
CustomJSLib expectedJSLib = new CustomJSLib(
|
||||
"TestLib", Set.of("accessor1"), "url", "docsUrl", "1" + ".0", "defs_string");
|
||||
|
|
@ -978,10 +981,10 @@ public class ImportApplicationServiceTests {
|
|||
assertEquals(expectedJSLib.getDocsUrl(), importedJSLib.getDocsUrl());
|
||||
assertEquals(expectedJSLib.getVersion(), importedJSLib.getVersion());
|
||||
assertEquals(expectedJSLib.getDefs(), importedJSLib.getDefs());
|
||||
assertEquals(1, application.getUnpublishedCustomJSLibs().size());
|
||||
assertEquals(
|
||||
getDTOFromCustomJSLib(expectedJSLib),
|
||||
application.getUnpublishedCustomJSLibs().toArray()[0]);
|
||||
// although the imported list had only one jsLib entry, the other entry comes from ensuring an xml
|
||||
// parser entry
|
||||
// for backward compatibility
|
||||
assertEquals(2, application.getUnpublishedCustomJSLibs().size());
|
||||
|
||||
assertThat(application.getName()).isEqualTo("valid_application");
|
||||
assertThat(application.getWorkspaceId()).isNotNull();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user