chore: support localstorage APIs using appsmith store functions (#19789)
## Description Most JS libraries are written with the intent to run of browsers main thread and not a web worker. JS libraries relies on the support for local storage APIs fail because web worker do not have access to local storage APIs. Examples of libraries that rely on localStorage include Mixpanel-browser, Supabasev2 etc. - Mocks localStorage API by using the respective store operation under the hood. - Autocomplete will not suggest localStorage APIs to promote the use of appsmith store functions. Fixes #19792 ### Type of change - Chore (housekeeping or task changes that don't impact user perception) ### How Has This Been Tested? - Manual 1. Instal supobase - https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.4.0/dist/umd/supabase.min.js and verify that its working properly 2. Instal recommend libraries and verify that it is getting installed properly > 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 - [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 - [x] 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: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test
This commit is contained in:
parent
98a29b890f
commit
e4a84b7c23
|
|
@ -4,7 +4,6 @@ import {
|
|||
createEvaluationContext,
|
||||
EvalContext,
|
||||
} from "workers/Evaluation/evaluate";
|
||||
import uniqueId from "lodash/uniqueId";
|
||||
import { MessageType } from "utils/MessageUtil";
|
||||
import {
|
||||
addDataTreeToContext,
|
||||
|
|
|
|||
30
app/client/src/workers/Evaluation/fns/LocalStorage.ts
Normal file
30
app/client/src/workers/Evaluation/fns/LocalStorage.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import get from "lodash/get";
|
||||
|
||||
export default function initLocalStorage(ctx: typeof globalThis) {
|
||||
function getItem(key: string) {
|
||||
//@ts-expect-error no types
|
||||
return get(ctx.appsmith.store, key);
|
||||
}
|
||||
function setItem(key: string, value: any) {
|
||||
//@ts-expect-error no types
|
||||
ctx.storeValue(key, value);
|
||||
}
|
||||
function removeItem(key: string) {
|
||||
//@ts-expect-error no types
|
||||
ctx.removeValue(key);
|
||||
}
|
||||
function clear() {
|
||||
//@ts-expect-error no types
|
||||
ctx.clearStore();
|
||||
}
|
||||
const localStorage = {
|
||||
getItem,
|
||||
setItem,
|
||||
removeItem,
|
||||
clear,
|
||||
};
|
||||
Object.defineProperty(ctx, "localStorage", {
|
||||
enumerable: false,
|
||||
value: localStorage,
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
import { addPlatformFunctionsToEvalContext } from "ce/workers/Evaluation/Actions";
|
||||
import { ENTITY_TYPE } from "design-system";
|
||||
import { PluginType } from "entities/Action";
|
||||
import { DataTree } from "entities/DataTree/dataTreeFactory";
|
||||
import { createEvaluationContext } from "workers/Evaluation/evaluate";
|
||||
import initLocalStorage from "../LocalStorage";
|
||||
|
||||
describe("Tests localStorage implementation in worker", () => {
|
||||
const dataTree: DataTree = {
|
||||
action1: {
|
||||
actionId: "123",
|
||||
pluginId: "",
|
||||
data: {},
|
||||
config: {},
|
||||
datasourceUrl: "",
|
||||
pluginType: PluginType.API,
|
||||
dynamicBindingPathList: [],
|
||||
name: "action1",
|
||||
bindingPaths: {},
|
||||
reactivePaths: {},
|
||||
isLoading: false,
|
||||
run: {},
|
||||
clear: {},
|
||||
responseMeta: { isExecutionSuccess: false },
|
||||
ENTITY_TYPE: ENTITY_TYPE.ACTION,
|
||||
dependencyMap: {},
|
||||
logBlackList: {},
|
||||
},
|
||||
};
|
||||
const workerEventMock = jest.fn();
|
||||
self.postMessage = workerEventMock;
|
||||
self.ALLOW_ASYNC = true;
|
||||
const evalContext = createEvaluationContext({
|
||||
dataTree,
|
||||
resolvedFunctions: {},
|
||||
isTriggerBased: true,
|
||||
context: {},
|
||||
});
|
||||
|
||||
addPlatformFunctionsToEvalContext(evalContext);
|
||||
initLocalStorage(evalContext as any);
|
||||
it("setItem()", () => {
|
||||
const key = "some";
|
||||
const value = "thing";
|
||||
jest.useFakeTimers();
|
||||
evalContext.localStorage.setItem(key, value);
|
||||
jest.runAllTimers();
|
||||
expect(workerEventMock).lastCalledWith({
|
||||
messageType: "DEFAULT",
|
||||
body: {
|
||||
data: [
|
||||
{
|
||||
payload: {
|
||||
key: "some",
|
||||
value: "thing",
|
||||
persist: true,
|
||||
},
|
||||
type: "STORE_VALUE",
|
||||
},
|
||||
],
|
||||
method: "PROCESS_STORE_UPDATES",
|
||||
},
|
||||
});
|
||||
});
|
||||
it("getItem()", () => {
|
||||
expect(evalContext.localStorage.getItem("some")).toBe("thing");
|
||||
});
|
||||
it("removeItem()", () => {
|
||||
evalContext.localStorage.removeItem("some");
|
||||
jest.runAllTimers();
|
||||
expect(workerEventMock).lastCalledWith({
|
||||
messageType: "DEFAULT",
|
||||
body: {
|
||||
data: [
|
||||
{
|
||||
payload: {
|
||||
key: "some",
|
||||
},
|
||||
type: "REMOVE_VALUE",
|
||||
},
|
||||
],
|
||||
method: "PROCESS_STORE_UPDATES",
|
||||
},
|
||||
});
|
||||
});
|
||||
it("clear()", () => {
|
||||
evalContext.localStorage.clear();
|
||||
jest.runAllTimers();
|
||||
expect(workerEventMock).lastCalledWith({
|
||||
messageType: "DEFAULT",
|
||||
body: {
|
||||
data: [
|
||||
{
|
||||
payload: null,
|
||||
type: "CLEAR_STORE",
|
||||
},
|
||||
],
|
||||
method: "PROCESS_STORE_UPDATES",
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -20,7 +20,7 @@ export function initStoreFns(ctx: typeof globalThis) {
|
|||
persist,
|
||||
},
|
||||
};
|
||||
set(self, ["appsmith", "store", key], value);
|
||||
set(ctx, ["appsmith", "store", key], value);
|
||||
triggerCollector.collect(requestPayload);
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
|
@ -33,14 +33,14 @@ export function initStoreFns(ctx: typeof globalThis) {
|
|||
},
|
||||
};
|
||||
//@ts-expect-error no types for store
|
||||
delete self.appsmith.store[key];
|
||||
delete ctx.appsmith.store[key];
|
||||
triggerCollector.collect(requestPayload);
|
||||
return Promise.resolve({});
|
||||
}
|
||||
|
||||
function clearStore() {
|
||||
//@ts-expect-error no types for store
|
||||
self.appsmith.store = {};
|
||||
ctx.appsmith.store = {};
|
||||
triggerCollector.collect({
|
||||
type: "CLEAR_STORE",
|
||||
payload: null,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import overrideTimeout from "../TimeoutOverride";
|
|||
import { EvalWorkerSyncRequest } from "../types";
|
||||
import userLogs from "../UserLog";
|
||||
import { addPlatformFunctionsToEvalContext } from "@appsmith/workers/Evaluation/Actions";
|
||||
import initLocalStorage from "../fns/LocalStorage";
|
||||
|
||||
export default function() {
|
||||
const libraries = resetJSLibraries();
|
||||
|
|
@ -26,6 +27,7 @@ export default function() {
|
|||
interceptAndOverrideHttpRequest();
|
||||
setupDOM();
|
||||
addPlatformFunctionsToEvalContext(self);
|
||||
initLocalStorage(self);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user