feat: Add action to open property control with error in a widget (#33070)

## Description
A set of DUCK type, action and saga that opens the first property
control with error for a given `widgetId`.
Note: This assumes that an error exists when calling the action.

Fixes #33073

## Automation

/ok-to-test tags="@tag.Anvil"

### 🔍 Cypress test results
<!-- This is an auto-generated comment: Cypress test results  -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/8906908304>
> Commit: 3e397ff84c830bd64b4652b2bbddad987ed7414a
> Cypress dashboard url: <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=8906908304&attempt=1"
target="_blank">Click here!</a>

<!-- end of auto-generated comment: Cypress test results  -->









## Communication
Should the DevRel and Marketing teams inform users about this change?
- [ ] Yes
- [x] No
This commit is contained in:
Abhinav Jha 2024-05-01 13:51:00 +05:30 committed by GitHub
parent 08ca04a09c
commit 10faa6a36d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 69 additions and 3 deletions

View File

@ -40,4 +40,6 @@ export enum AnvilReduxActionTypes {
ANVIL_SPACE_DISTRIBUTION_STOP = "ANVIL_SPACE_DISTRIBUTION_STOP",
ANVIL_SET_HIGHLIGHT_SHOWN = "ANVIL_SET_HIGHLIGHT_SHOWN",
ANVIL_WIDGET_SELECTION_CLICK = "ANVIL_WIDGET_SELECTION_CLICK",
// Until the IDE or Integrations Pod provides an API
DEBUG_WIDGET = "DEBUG_WIDGET",
}

View File

@ -22,3 +22,13 @@ export const selectAnvilWidget = (widgetId: string, evt: CustomEvent) => {
},
};
};
// This is a stopgap measure until #33014 is resolved
export const debugWidget = (widgetId: string) => {
return {
type: AnvilReduxActionTypes.DEBUG_WIDGET,
payload: {
widgetId,
},
};
};

View File

@ -1,17 +1,26 @@
import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants";
import type { AppState } from "@appsmith/reducers";
import type { DSLWidget } from "WidgetProvider/constants";
import { focusWidget } from "actions/widgetActions";
import { selectWidgetInitAction } from "actions/widgetSelectionActions";
import get from "lodash/get";
import log from "loglevel";
import { put, select, takeLatest } from "redux-saga/effects";
import { SelectionRequestType } from "sagas/WidgetSelectUtils";
import { getWidget } from "sagas/selectors";
import { getIsPropertyPaneVisible } from "selectors/propertyPaneSelectors";
import {
getFocusedParentToOpen,
isWidgetSelected,
shouldWidgetIgnoreClicksSelector,
} from "selectors/widgetSelectors";
import { EVAL_ERROR_PATH } from "utils/DynamicBindingUtils";
import { NavigationMethod } from "utils/history";
import type { WidgetProps } from "widgets/BaseWidget";
import { AnvilReduxActionTypes } from "../actions/actionTypes";
import { setActiveEditorField } from "actions/activeFieldActions";
import { setFocusablePropertyPaneField } from "actions/propertyPaneActions";
import { setEvalPopupState } from "actions/editorContextActions";
import type { ReduxAction } from "@appsmith/constants/ReduxActionConstants";
/**
* This saga selects widgets in the Anvil Layout system
@ -76,6 +85,51 @@ export function* selectAnvilWidget(
log.debug("Time taken to select widget", performance.now() - start, "ms");
}
export default function* selectAnvilWidgetSaga() {
yield takeLatest("ANVIL_WIDGET_SELECTION_CLICK", selectAnvilWidget);
/**
* A function that loops through all the entries in the error object and finds the first error path
* @param errors The error object from evaluations
* @param widget The widget in which the error occured
* @returns The full property path of the property with the error
*/
function getErrorPropertyPath(
errors: Record<string, Array<unknown>>,
widget: DSLWidget,
) {
for (const [key, value] of Object.entries(errors)) {
if (value && value.length > 0) {
return `${widget.widgetName}.${key}`;
}
}
}
// This is a stopgap measure until #33014 is resolved
export function* debugWidget(action: ReduxAction<{ widgetId: string }>) {
const widgetId = action.payload.widgetId;
const widget: DSLWidget = yield select(getWidget, widgetId);
const widgetName: string = widget.widgetName;
const errors: Record<string, Array<unknown>> = yield select(
(state: AppState) =>
get(state.evaluations.tree[widgetName], EVAL_ERROR_PATH, {}),
);
const fullPath = getErrorPropertyPath(errors, widget);
if (fullPath && fullPath.length > 0) {
yield put(setActiveEditorField(fullPath));
yield put(setFocusablePropertyPaneField(fullPath));
yield put(
setEvalPopupState(fullPath, {
type: false,
value: true,
example: false,
}),
);
}
}
export default function* selectAnvilWidgetSaga() {
yield takeLatest(AnvilReduxActionTypes.DEBUG_WIDGET, debugWidget);
yield takeLatest(
AnvilReduxActionTypes.ANVIL_WIDGET_SELECTION_CLICK,
selectAnvilWidget,
);
}