fix: Show JS Function data in autocompletion hints (#19811)
## Description This PR adds JS function data to autocompletion hints Fixes #15909 <img width="278" alt="Screenshot 2023-01-16 at 20 35 55" src="https://user-images.githubusercontent.com/46670083/212754461-68844350-5d23-4b50-af1f-675b7719dc49.png"> ## Type of change - Bug fix (non-breaking change which fixes an issue) ## How Has This Been Tested? 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: - [ ] 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
dffe5890fb
commit
a1b07e21c7
|
|
@ -0,0 +1,37 @@
|
|||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||
import { WIDGET } from "../../../../locators/WidgetLocators";
|
||||
|
||||
const jsEditor = ObjectsRegistry.JSEditor,
|
||||
ee = ObjectsRegistry.EntityExplorer,
|
||||
agHelper = ObjectsRegistry.AggregateHelper,
|
||||
propPane = ObjectsRegistry.PropertyPane,
|
||||
CommonLocators = ObjectsRegistry.CommonLocators;
|
||||
|
||||
describe("JS Function Execution", function() {
|
||||
before(() => {
|
||||
ee.DragDropWidgetNVerify(WIDGET.BUTTON, 200, 200);
|
||||
});
|
||||
it("1. Shows js function data as part of autocompletion hints", function() {
|
||||
jsEditor.CreateJSObject(
|
||||
`export default {
|
||||
myFun1: ()=>{
|
||||
return "yes"
|
||||
},
|
||||
myFun2:()=>{
|
||||
return [{name: "test"}]
|
||||
}
|
||||
}`,
|
||||
{
|
||||
paste: true,
|
||||
completeReplace: true,
|
||||
toRun: false,
|
||||
shouldCreateNewJSObj: true,
|
||||
prettify: false,
|
||||
},
|
||||
);
|
||||
ee.SelectEntityByName("Button1", "Widgets");
|
||||
propPane.EnterJSContext("onClick", `{{JSObject1.`, true, false);
|
||||
agHelper.AssertContains("myFun1.data");
|
||||
agHelper.AssertContains("myFun2.data");
|
||||
});
|
||||
});
|
||||
|
|
@ -91,7 +91,10 @@ import { FormEvaluationState } from "reducers/evaluationReducers/formEvaluationR
|
|||
import { FormEvalActionPayload } from "./FormEvaluationSaga";
|
||||
import { getSelectedAppTheme } from "selectors/appThemingSelectors";
|
||||
import { resetWidgetsMetaState, updateMetaState } from "actions/metaActions";
|
||||
import { getAllActionValidationConfig } from "selectors/entitiesSelector";
|
||||
import {
|
||||
getAllActionValidationConfig,
|
||||
getAllJSActionsData,
|
||||
} from "selectors/entitiesSelector";
|
||||
import {
|
||||
DataTree,
|
||||
UnEvalTree,
|
||||
|
|
@ -229,6 +232,7 @@ export function* evaluateTreeSaga(
|
|||
yield call(evalErrorHandler as any, errors, updatedDataTree, evaluationOrder);
|
||||
|
||||
if (appMode !== APP_MODE.PUBLISHED) {
|
||||
const jsData: Record<string, unknown> = yield select(getAllJSActionsData);
|
||||
yield call(makeUpdateJSCollection, jsUpdates);
|
||||
yield fork(
|
||||
logSuccessfulBindings,
|
||||
|
|
@ -243,6 +247,7 @@ export function* evaluateTreeSaga(
|
|||
updatedDataTree,
|
||||
unEvalUpdates,
|
||||
isCreateFirstTree,
|
||||
jsData,
|
||||
);
|
||||
}
|
||||
yield put(setDependencyMap(dependencies));
|
||||
|
|
@ -566,6 +571,7 @@ function* evaluationChangeListenerSaga(): any {
|
|||
|
||||
if (shouldProcessBatchedAction(action)) {
|
||||
const postEvalActions = getPostEvalActions(action);
|
||||
|
||||
yield call(
|
||||
evaluateTreeSaga,
|
||||
postEvalActions,
|
||||
|
|
|
|||
|
|
@ -342,6 +342,7 @@ export function* updateTernDefinitions(
|
|||
dataTree: DataTree,
|
||||
updates: DataTreeDiff[],
|
||||
isCreateFirstTree: boolean,
|
||||
jsData: Record<string, unknown> = {},
|
||||
) {
|
||||
const shouldUpdate: boolean =
|
||||
isCreateFirstTree ||
|
||||
|
|
@ -365,6 +366,7 @@ export function* updateTernDefinitions(
|
|||
const { def, entityInfo } = dataTreeTypeDefCreator(
|
||||
treeWithoutPrivateWidgets,
|
||||
!!featureFlags.JS_EDITOR,
|
||||
jsData,
|
||||
);
|
||||
CodemirrorTernService.updateDef("DATA_TREE", def, entityInfo);
|
||||
const end = performance.now();
|
||||
|
|
|
|||
|
|
@ -916,3 +916,22 @@ export const selectLibrariesForExplorer = createSelector(
|
|||
return [...queuedInstalls, ...libs];
|
||||
},
|
||||
);
|
||||
|
||||
export const getAllJSActionsData = (state: AppState) => {
|
||||
const jsActionsData: Record<string, unknown> = {};
|
||||
const jsCollections = state.entities.jsActions;
|
||||
jsCollections.forEach((collection) => {
|
||||
if (collection.data) {
|
||||
Object.keys(collection.data).forEach((actionId) => {
|
||||
const jsAction = getJSActions(state, collection.config.id).find(
|
||||
(action) => action.id === actionId,
|
||||
);
|
||||
if (jsAction) {
|
||||
jsActionsData[`${collection.config.name}.${jsAction.name}`] =
|
||||
collection.data?.[actionId];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return jsActionsData;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { Variable } from "entities/JSCollection";
|
|||
export const dataTreeTypeDefCreator = (
|
||||
dataTree: DataTree,
|
||||
isJSEditorEnabled: boolean,
|
||||
jsData: Record<string, unknown> = {},
|
||||
): { def: Def; entityInfo: Map<string, DataTreeDefEntityInformation> } => {
|
||||
// When there is a complex data type, we store it in extra def and refer to it in the def
|
||||
const extraDefsToDefine: Def = {};
|
||||
|
|
@ -67,15 +68,15 @@ export const dataTreeTypeDefCreator = (
|
|||
const metaObj = entity.meta;
|
||||
const jsPropertiesDef: Def = {};
|
||||
|
||||
for (const key in metaObj) {
|
||||
// const jsFunctionObj = metaObj[key];
|
||||
// const { arguments: args } = jsFunctionObj;
|
||||
// const argsTypeString = getFunctionsArgsType(args);
|
||||
// As we don't show args we avoid to get args def of function
|
||||
// we will also need to check performance implications here
|
||||
|
||||
const argsTypeString = getFunctionsArgsType([]);
|
||||
jsPropertiesDef[key] = argsTypeString;
|
||||
for (const funcName in metaObj) {
|
||||
const funcTypeDef = generateJSFunctionTypeDef(
|
||||
jsData,
|
||||
`${entity.name}.${funcName}`,
|
||||
extraDefsToDefine,
|
||||
);
|
||||
jsPropertiesDef[funcName] = funcTypeDef;
|
||||
// To also show funcName.data in autocompletion hint, we explictly add it here
|
||||
jsPropertiesDef[`${funcName}.data`] = funcTypeDef.data;
|
||||
}
|
||||
|
||||
for (let i = 0; i < entity.variables.length; i++) {
|
||||
|
|
@ -197,3 +198,14 @@ export const getFunctionsArgsType = (args: Variable[]): string => {
|
|||
);
|
||||
return argsTypeString ? `fn(${argsTypeString})` : `fn()`;
|
||||
};
|
||||
|
||||
export function generateJSFunctionTypeDef(
|
||||
jsData: Record<string, unknown> = {},
|
||||
fullFunctionName: string,
|
||||
extraDefs: ExtraDef,
|
||||
) {
|
||||
return {
|
||||
"!type": getFunctionsArgsType([]),
|
||||
data: generateTypeDef(jsData[fullFunctionName], extraDefs),
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user