feat: [Context Switching] maintain focus of code editor fields (#18240)
This commit is contained in:
parent
c72f865962
commit
17dbe63ed3
|
|
@ -31,7 +31,7 @@ describe("Canvas context Property Pane", function() {
|
||||||
cy.focusCodeInput(propertyControlSelector);
|
cy.focusCodeInput(propertyControlSelector);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
cy.assertSoftFocusOnPropertyPane(propertyControlSelector);
|
cy.assertCursorOnCodeInput(propertyControlSelector);
|
||||||
},
|
},
|
||||||
"Button1",
|
"Button1",
|
||||||
);
|
);
|
||||||
|
|
@ -160,7 +160,7 @@ describe("Canvas context Property Pane", function() {
|
||||||
cy.focusCodeInput(propertyControlSelector);
|
cy.focusCodeInput(propertyControlSelector);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
cy.assertSoftFocusOnPropertyPane(propertyControlSelector);
|
cy.assertCursorOnCodeInput(propertyControlSelector);
|
||||||
},
|
},
|
||||||
"Table1",
|
"Table1",
|
||||||
);
|
);
|
||||||
|
|
@ -241,7 +241,7 @@ describe("Canvas context Property Pane", function() {
|
||||||
cy.focusCodeInput(propertyControlSelector);
|
cy.focusCodeInput(propertyControlSelector);
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
cy.assertSoftFocusOnPropertyPane(propertyControlSelector);
|
cy.assertCursorOnCodeInput(propertyControlSelector);
|
||||||
},
|
},
|
||||||
"Table1",
|
"Table1",
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import reconnectDatasourceModal from "../../../../locators/ReconnectLocators";
|
import reconnectDatasourceModal from "../../../../locators/ReconnectLocators";
|
||||||
const apiwidget = require("../../../../locators/apiWidgetslocator.json");
|
const apiwidget = require("../../../../locators/apiWidgetslocator.json");
|
||||||
|
const queryLocators = require("../../../../locators/QueryEditor.json");
|
||||||
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
import { ObjectsRegistry } from "../../../../support/Objects/Registry";
|
||||||
|
|
||||||
const homePage = ObjectsRegistry.HomePage;
|
const homePage = ObjectsRegistry.HomePage;
|
||||||
|
|
@ -88,7 +89,7 @@ describe("MaintainContext&Focus", function() {
|
||||||
cy.get(`.t--entity-name:contains("Page1")`).click();
|
cy.get(`.t--entity-name:contains("Page1")`).click();
|
||||||
|
|
||||||
cy.get(".t--widget-name").should("have.text", "Text1");
|
cy.get(".t--widget-name").should("have.text", "Text1");
|
||||||
cy.assertSoftFocusOnPropertyPane(".t--property-control-text", {
|
cy.assertCursorOnCodeInput(".t--property-control-text", {
|
||||||
ch: 2,
|
ch: 2,
|
||||||
line: 0,
|
line: 0,
|
||||||
});
|
});
|
||||||
|
|
@ -195,4 +196,18 @@ describe("MaintainContext&Focus", function() {
|
||||||
// Validate if section with index 1 is expanded
|
// Validate if section with index 1 is expanded
|
||||||
dataSources.AssertSectionCollapseState(1, false);
|
dataSources.AssertSectionCollapseState(1, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("10. Maintain focus of form control inputs", () => {
|
||||||
|
ee.SelectEntityByName("SQL_Query");
|
||||||
|
dataSources.ToggleUsePreparedStatement(false);
|
||||||
|
cy.SearchEntityandOpen("S3_Query");
|
||||||
|
cy.get(queryLocators.querySettingsTab).click();
|
||||||
|
cy.setQueryTimeout(10000);
|
||||||
|
|
||||||
|
cy.SearchEntityandOpen("SQL_Query");
|
||||||
|
cy.get(".t--form-control-SWITCH input").should("be.focused");
|
||||||
|
cy.SearchEntityandOpen("S3_Query");
|
||||||
|
cy.get(queryLocators.querySettingsTab).click();
|
||||||
|
cy.xpath(queryLocators.queryTimeout).should("be.focused");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -617,7 +617,7 @@ Cypress.Commands.add(
|
||||||
);
|
);
|
||||||
|
|
||||||
Cypress.Commands.add(
|
Cypress.Commands.add(
|
||||||
"assertSoftFocusOnPropertyPane",
|
"assertSoftFocusOnCodeInput",
|
||||||
($selector, cursor = { ch: 0, line: 0 }) => {
|
($selector, cursor = { ch: 0, line: 0 }) => {
|
||||||
cy.EnableAllCodeEditors();
|
cy.EnableAllCodeEditors();
|
||||||
cy.get($selector)
|
cy.get($selector)
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@ import {
|
||||||
PropertyPanelContext,
|
PropertyPanelContext,
|
||||||
} from "reducers/uiReducers/editorContextReducer";
|
} from "reducers/uiReducers/editorContextReducer";
|
||||||
|
|
||||||
export const setFocusableCodeEditorField = (path: string | undefined) => {
|
export const setFocusableInputField = (path: string | undefined) => {
|
||||||
return {
|
return {
|
||||||
type: ReduxActionTypes.SET_FOCUSABLE_CODE_EDITOR_FIELD,
|
type: ReduxActionTypes.SET_FOCUSABLE_INPUT_FIELD,
|
||||||
payload: { path },
|
payload: { path },
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,6 @@ export const setSelectedPropertyTabIndex = (selectedIndex: number) => {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const setFocusablePropertyPaneField = (path?: string) => {
|
|
||||||
return {
|
|
||||||
type: ReduxActionTypes.SET_FOCUSABLE_PROPERTY_FIELD,
|
|
||||||
payload: { path },
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setSelectedPropertyPanel = (
|
export const setSelectedPropertyPanel = (
|
||||||
path: string | undefined,
|
path: string | undefined,
|
||||||
index: number,
|
index: number,
|
||||||
|
|
|
||||||
|
|
@ -687,10 +687,6 @@ export const ReduxActionTypes = {
|
||||||
FETCH_CURRENT_TENANT_CONFIG: "FETCH_CURRENT_TENANT_CONFIG",
|
FETCH_CURRENT_TENANT_CONFIG: "FETCH_CURRENT_TENANT_CONFIG",
|
||||||
FETCH_CURRENT_TENANT_CONFIG_SUCCESS: "FETCH_CURRENT_TENANT_CONFIG_SUCCESS",
|
FETCH_CURRENT_TENANT_CONFIG_SUCCESS: "FETCH_CURRENT_TENANT_CONFIG_SUCCESS",
|
||||||
SET_FOCUS_HISTORY: "SET_FOCUS_HISTORY",
|
SET_FOCUS_HISTORY: "SET_FOCUS_HISTORY",
|
||||||
SET_FOCUSABLE_CODE_EDITOR_FIELD: "SET_FOCUSABLE_CODE_EDITOR_FIELD",
|
|
||||||
GENERATE_KEY_AND_SET_FOCUSABLE_CODE_EDITOR_FIELD:
|
|
||||||
"GENERATE_KEY_AND_SET_FOCUSABLE_CODE_EDITOR_FIELD",
|
|
||||||
SET_FOCUSABLE_PROPERTY_FIELD: "SET_FOCUSABLE_PROPERTY_FIELD",
|
|
||||||
ROUTE_CHANGED: "ROUTE_CHANGED",
|
ROUTE_CHANGED: "ROUTE_CHANGED",
|
||||||
PAGE_CHANGED: "PAGE_CHANGED",
|
PAGE_CHANGED: "PAGE_CHANGED",
|
||||||
SET_API_PANE_CONFIG_SELECTED_TAB: "SET_API_PANE_CONFIG_SELECTED_TAB",
|
SET_API_PANE_CONFIG_SELECTED_TAB: "SET_API_PANE_CONFIG_SELECTED_TAB",
|
||||||
|
|
@ -698,6 +694,7 @@ export const ReduxActionTypes = {
|
||||||
SET_API_PANE_RESPONSE_PANE_HEIGHT: "SET_API_PANE_RESPONSE_PANE_HEIGHT",
|
SET_API_PANE_RESPONSE_PANE_HEIGHT: "SET_API_PANE_RESPONSE_PANE_HEIGHT",
|
||||||
SET_API_RIGHT_PANE_SELECTED_TAB: "SET_API_RIGHT_PANE_SELECTED_TAB",
|
SET_API_RIGHT_PANE_SELECTED_TAB: "SET_API_RIGHT_PANE_SELECTED_TAB",
|
||||||
SET_EDITOR_FIELD_FOCUS: "SET_EDITOR_FIELD_FOCUS",
|
SET_EDITOR_FIELD_FOCUS: "SET_EDITOR_FIELD_FOCUS",
|
||||||
|
SET_FOCUSABLE_INPUT_FIELD: "SET_FOCUSABLE_INPUT_FIELD",
|
||||||
SET_CODE_EDITOR_CURSOR: "SET_CODE_EDITOR_CURSOR",
|
SET_CODE_EDITOR_CURSOR: "SET_CODE_EDITOR_CURSOR",
|
||||||
SET_CODE_EDITOR_CURSOR_HISTORY: "SET_CODE_EDITOR_CURSOR_HISTORY",
|
SET_CODE_EDITOR_CURSOR_HISTORY: "SET_CODE_EDITOR_CURSOR_HISTORY",
|
||||||
SET_EVAL_POPUP_STATE: "SET_EVAL_POPUP_STATE",
|
SET_EVAL_POPUP_STATE: "SET_EVAL_POPUP_STATE",
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ import { interactionAnalyticsEvent } from "utils/AppsmithUtils";
|
||||||
import { AdditionalDynamicDataTree } from "utils/autocomplete/customTreeTypeDefCreator";
|
import { AdditionalDynamicDataTree } from "utils/autocomplete/customTreeTypeDefCreator";
|
||||||
import {
|
import {
|
||||||
getCodeEditorLastCursorPosition,
|
getCodeEditorLastCursorPosition,
|
||||||
getIsCodeEditorFocused,
|
getIsInputFieldFocused,
|
||||||
} from "selectors/editorContextSelectors";
|
} from "selectors/editorContextSelectors";
|
||||||
import {
|
import {
|
||||||
CodeEditorFocusState,
|
CodeEditorFocusState,
|
||||||
|
|
@ -1153,7 +1153,7 @@ const mapStateToProps = (state: AppState, props: EditorProps) => ({
|
||||||
pluginIdToImageLocation: getPluginIdToImageLocation(state),
|
pluginIdToImageLocation: getPluginIdToImageLocation(state),
|
||||||
recentEntities: getRecentEntityIds(state),
|
recentEntities: getRecentEntityIds(state),
|
||||||
lintErrors: getEntityLintErrors(state, props.dataTreePath),
|
lintErrors: getEntityLintErrors(state, props.dataTreePath),
|
||||||
editorIsFocused: getIsCodeEditorFocused(state, getEditorIdentifier(props)),
|
editorIsFocused: getIsInputFieldFocused(state, getEditorIdentifier(props)),
|
||||||
editorLastCursorPosition: getCodeEditorLastCursorPosition(
|
editorLastCursorPosition: getCodeEditorLastCursorPosition(
|
||||||
state,
|
state,
|
||||||
getEditorIdentifier(props),
|
getEditorIdentifier(props),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import {
|
||||||
getCodeEditorHistory,
|
getCodeEditorHistory,
|
||||||
getExplorerSwitchIndex,
|
getExplorerSwitchIndex,
|
||||||
getPropertyPanelState,
|
getPropertyPanelState,
|
||||||
getFocusableCodeEditorField,
|
getFocusableInputField,
|
||||||
getSelectedCanvasDebuggerTab,
|
getSelectedCanvasDebuggerTab,
|
||||||
getWidgetSelectedPropertyTabIndex,
|
getWidgetSelectedPropertyTabIndex,
|
||||||
} from "selectors/editorContextSelectors";
|
} from "selectors/editorContextSelectors";
|
||||||
|
|
@ -31,7 +31,7 @@ import {
|
||||||
setPanelPropertiesState,
|
setPanelPropertiesState,
|
||||||
setWidgetSelectedPropertyTabIndex,
|
setWidgetSelectedPropertyTabIndex,
|
||||||
} from "actions/editorContextActions";
|
} from "actions/editorContextActions";
|
||||||
import { setFocusableCodeEditorField } from "actions/editorContextActions";
|
import { setFocusableInputField } from "actions/editorContextActions";
|
||||||
import {
|
import {
|
||||||
getAllDatasourceCollapsibleState,
|
getAllDatasourceCollapsibleState,
|
||||||
getSelectedWidgets,
|
getSelectedWidgets,
|
||||||
|
|
@ -75,17 +75,13 @@ import {
|
||||||
setPropertyPaneWidthAction,
|
setPropertyPaneWidthAction,
|
||||||
setSelectedPropertyPanels,
|
setSelectedPropertyPanels,
|
||||||
} from "actions/propertyPaneActions";
|
} from "actions/propertyPaneActions";
|
||||||
import {
|
import { setAllPropertySectionState } from "actions/propertyPaneActions";
|
||||||
setAllPropertySectionState,
|
|
||||||
setFocusablePropertyPaneField,
|
|
||||||
} from "actions/propertyPaneActions";
|
|
||||||
import { setCanvasDebuggerSelectedTab } from "actions/debuggerActions";
|
import { setCanvasDebuggerSelectedTab } from "actions/debuggerActions";
|
||||||
import {
|
import {
|
||||||
setAllDatasourceCollapsible,
|
setAllDatasourceCollapsible,
|
||||||
setDatasourceViewMode,
|
setDatasourceViewMode,
|
||||||
} from "actions/datasourceActions";
|
} from "actions/datasourceActions";
|
||||||
import { PluginPackageName } from "entities/Action";
|
import { PluginPackageName } from "entities/Action";
|
||||||
import { getFocusablePropertyPaneField } from "selectors/propertyPaneSelectors";
|
|
||||||
|
|
||||||
export enum FocusElement {
|
export enum FocusElement {
|
||||||
ApiPaneConfigTabs = "ApiPaneConfigTabs",
|
ApiPaneConfigTabs = "ApiPaneConfigTabs",
|
||||||
|
|
@ -105,8 +101,6 @@ export enum FocusElement {
|
||||||
JSPaneConfigTabs = "JSPaneConfigTabs",
|
JSPaneConfigTabs = "JSPaneConfigTabs",
|
||||||
JSPaneResponseTabs = "JSPaneResponseTabs",
|
JSPaneResponseTabs = "JSPaneResponseTabs",
|
||||||
JSPaneResponseHeight = "JSPaneResponseHeight",
|
JSPaneResponseHeight = "JSPaneResponseHeight",
|
||||||
CodeEditor = "CodeEditor",
|
|
||||||
PropertyField = "PropertyField",
|
|
||||||
PropertySections = "PropertySections",
|
PropertySections = "PropertySections",
|
||||||
PropertyTabs = "PropertyTabs",
|
PropertyTabs = "PropertyTabs",
|
||||||
PropertyPanelContext = "PropertyPanelContext",
|
PropertyPanelContext = "PropertyPanelContext",
|
||||||
|
|
@ -114,6 +108,7 @@ export enum FocusElement {
|
||||||
SelectedPropertyPanel = "SelectedPropertyPanel",
|
SelectedPropertyPanel = "SelectedPropertyPanel",
|
||||||
SelectedWidgets = "SelectedWidgets",
|
SelectedWidgets = "SelectedWidgets",
|
||||||
SubEntityCollapsibleState = "SubEntityCollapsibleState",
|
SubEntityCollapsibleState = "SubEntityCollapsibleState",
|
||||||
|
InputField = "InputField",
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config = {
|
type Config = {
|
||||||
|
|
@ -211,9 +206,9 @@ export const FocusElementsConfig: Record<FocusEntity, Config[]> = {
|
||||||
],
|
],
|
||||||
[FocusEntity.JS_OBJECT]: [
|
[FocusEntity.JS_OBJECT]: [
|
||||||
{
|
{
|
||||||
name: FocusElement.CodeEditor,
|
name: FocusElement.InputField,
|
||||||
selector: getFocusableCodeEditorField,
|
selector: getFocusableInputField,
|
||||||
setter: setFocusableCodeEditorField,
|
setter: setFocusableInputField,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: FocusElement.JSPaneConfigTabs,
|
name: FocusElement.JSPaneConfigTabs,
|
||||||
|
|
@ -236,9 +231,9 @@ export const FocusElementsConfig: Record<FocusEntity, Config[]> = {
|
||||||
],
|
],
|
||||||
[FocusEntity.QUERY]: [
|
[FocusEntity.QUERY]: [
|
||||||
{
|
{
|
||||||
name: FocusElement.CodeEditor,
|
name: FocusElement.InputField,
|
||||||
selector: getFocusableCodeEditorField,
|
selector: getFocusableInputField,
|
||||||
setter: setFocusableCodeEditorField,
|
setter: setFocusableInputField,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: FocusElement.QueryPaneConfigTabs,
|
name: FocusElement.QueryPaneConfigTabs,
|
||||||
|
|
@ -267,18 +262,13 @@ export const FocusElementsConfig: Record<FocusEntity, Config[]> = {
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: FocusElement.PropertyField,
|
name: FocusElement.InputField,
|
||||||
selector: getFocusablePropertyPaneField,
|
selector: getFocusableInputField,
|
||||||
setter: setFocusablePropertyPaneField,
|
setter: setFocusableInputField,
|
||||||
defaultValue: "",
|
defaultValue: "",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[FocusEntity.API]: [
|
[FocusEntity.API]: [
|
||||||
{
|
|
||||||
name: FocusElement.CodeEditor,
|
|
||||||
selector: getFocusableCodeEditorField,
|
|
||||||
setter: setFocusableCodeEditorField,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: FocusElement.ApiPaneConfigTabs,
|
name: FocusElement.ApiPaneConfigTabs,
|
||||||
selector: getApiPaneConfigSelectedTabIndex,
|
selector: getApiPaneConfigSelectedTabIndex,
|
||||||
|
|
@ -302,6 +292,11 @@ export const FocusElementsConfig: Record<FocusEntity, Config[]> = {
|
||||||
setter: setApiPaneResponsePaneHeight,
|
setter: setApiPaneResponsePaneHeight,
|
||||||
defaultValue: ActionExecutionResizerHeight,
|
defaultValue: ActionExecutionResizerHeight,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: FocusElement.InputField,
|
||||||
|
selector: getFocusableInputField,
|
||||||
|
setter: setFocusableInputField,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: FocusElement.ApiRightPaneTabs,
|
name: FocusElement.ApiRightPaneTabs,
|
||||||
selector: getApiRightPaneSelectedTab,
|
selector: getApiRightPaneSelectedTab,
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import lightmodeThumbnail from "assets/icons/gifs/lightmode_thumbnail.png";
|
||||||
import darkmodeThumbnail from "assets/icons/gifs/darkmode_thumbnail.png";
|
import darkmodeThumbnail from "assets/icons/gifs/darkmode_thumbnail.png";
|
||||||
|
|
||||||
interface PaginationProps {
|
interface PaginationProps {
|
||||||
|
actionName: string;
|
||||||
onTestClick: (test?: "PREV" | "NEXT") => void;
|
onTestClick: (test?: "PREV" | "NEXT") => void;
|
||||||
paginationType: PaginationType;
|
paginationType: PaginationType;
|
||||||
theme?: EditorTheme;
|
theme?: EditorTheme;
|
||||||
|
|
@ -183,6 +184,7 @@ export default function Pagination(props: PaginationProps) {
|
||||||
border={CodeEditorBorder.ALL_SIDE}
|
border={CodeEditorBorder.ALL_SIDE}
|
||||||
className="t--apiFormPaginationPrev"
|
className="t--apiFormPaginationPrev"
|
||||||
fill={!!true}
|
fill={!!true}
|
||||||
|
focusElementName={`${props.actionName}.actionConfiguration.prev`}
|
||||||
height="100%"
|
height="100%"
|
||||||
name="actionConfiguration.prev"
|
name="actionConfiguration.prev"
|
||||||
theme={props.theme}
|
theme={props.theme}
|
||||||
|
|
@ -208,6 +210,7 @@ export default function Pagination(props: PaginationProps) {
|
||||||
border={CodeEditorBorder.ALL_SIDE}
|
border={CodeEditorBorder.ALL_SIDE}
|
||||||
className="t--apiFormPaginationNext"
|
className="t--apiFormPaginationNext"
|
||||||
fill={!!true}
|
fill={!!true}
|
||||||
|
focusElementName={`${props.actionName}.actionConfiguration.next`}
|
||||||
height="100%"
|
height="100%"
|
||||||
name="actionConfiguration.next"
|
name="actionConfiguration.next"
|
||||||
theme={props.theme}
|
theme={props.theme}
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ function RapidApiEditorForm(props: Props) {
|
||||||
title: "Pagination",
|
title: "Pagination",
|
||||||
panelComponent: (
|
panelComponent: (
|
||||||
<Pagination
|
<Pagination
|
||||||
|
actionName={props.apiName}
|
||||||
onTestClick={props.onRunClick}
|
onTestClick={props.onRunClick}
|
||||||
paginationType={props.paginationType}
|
paginationType={props.paginationType}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,7 @@ function ApiEditorForm(props: Props) {
|
||||||
formName={API_EDITOR_FORM_NAME}
|
formName={API_EDITOR_FORM_NAME}
|
||||||
paginationUIComponent={
|
paginationUIComponent={
|
||||||
<Pagination
|
<Pagination
|
||||||
|
actionName={actionName}
|
||||||
onTestClick={props.onRunClick}
|
onTestClick={props.onRunClick}
|
||||||
paginationType={props.paginationType}
|
paginationType={props.paginationType}
|
||||||
theme={theme}
|
theme={theme}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { ControlProps } from "components/formControls/BaseControl";
|
import { ControlProps } from "components/formControls/BaseControl";
|
||||||
import {
|
import {
|
||||||
EvaluationError,
|
EvaluationError,
|
||||||
|
|
@ -18,6 +18,15 @@ import { FormIcons } from "icons/FormIcons";
|
||||||
import { FormControlProps } from "./FormControl";
|
import { FormControlProps } from "./FormControl";
|
||||||
import { ToggleComponentToJsonHandler } from "components/editorComponents/form/ToggleComponentToJson";
|
import { ToggleComponentToJsonHandler } from "components/editorComponents/form/ToggleComponentToJson";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
import { useDispatch, useSelector } from "react-redux";
|
||||||
|
import { identifyEntityFromPath } from "navigation/FocusEntity";
|
||||||
|
import { AppState } from "@appsmith/reducers";
|
||||||
|
import {
|
||||||
|
getPropertyControlFocusElement,
|
||||||
|
shouldFocusOnPropertyControl,
|
||||||
|
} from "utils/editorContextUtils";
|
||||||
|
import { getIsInputFieldFocused } from "selectors/editorContextSelectors";
|
||||||
|
import { setFocusableInputField } from "actions/editorContextActions";
|
||||||
|
|
||||||
const FlexWrapper = styled.div`
|
const FlexWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -59,7 +68,48 @@ interface FormConfigProps extends FormControlProps {
|
||||||
// props.children will render the form element
|
// props.children will render the form element
|
||||||
export default function FormConfig(props: FormConfigProps) {
|
export default function FormConfig(props: FormConfigProps) {
|
||||||
let top, bottom;
|
let top, bottom;
|
||||||
|
const controlRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const entityInfo = identifyEntityFromPath(
|
||||||
|
window.location.pathname,
|
||||||
|
window.location.hash,
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleOnFocus = () => {
|
||||||
|
if (props.config.configProperty) {
|
||||||
|
// Need an additional identifier to trigger another render when configProperty
|
||||||
|
// are same for two different entitites
|
||||||
|
dispatch(
|
||||||
|
setFocusableInputField(
|
||||||
|
`${entityInfo.id}.${props.config.configProperty}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const shouldFocusPropertyPath: boolean = useSelector((state: AppState) =>
|
||||||
|
getIsInputFieldFocused(
|
||||||
|
state,
|
||||||
|
`${entityInfo.id}.${props.config.configProperty}`,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (shouldFocusPropertyPath) {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (shouldFocusOnPropertyControl(controlRef.current)) {
|
||||||
|
const focusableElement = getPropertyControlFocusElement(
|
||||||
|
controlRef.current,
|
||||||
|
);
|
||||||
|
focusableElement?.scrollIntoView({
|
||||||
|
block: "center",
|
||||||
|
behavior: "smooth",
|
||||||
|
});
|
||||||
|
focusableElement?.focus();
|
||||||
|
}
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}, [shouldFocusPropertyPath]);
|
||||||
if (props.multipleConfig?.length) {
|
if (props.multipleConfig?.length) {
|
||||||
top = (
|
top = (
|
||||||
<div style={{ display: "flex" }}>
|
<div style={{ display: "flex" }}>
|
||||||
|
|
@ -86,7 +136,11 @@ export default function FormConfig(props: FormConfigProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FormConfigWrapper controlType={props.config.controlType}>
|
<FormConfigWrapper
|
||||||
|
controlType={props.config.controlType}
|
||||||
|
onFocus={handleOnFocus}
|
||||||
|
ref={controlRef}
|
||||||
|
>
|
||||||
{props.config.controlType === "CHECKBOX" ? (
|
{props.config.controlType === "CHECKBOX" ? (
|
||||||
<>
|
<>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@ import {
|
||||||
THEME_BINDING_REGEX,
|
THEME_BINDING_REGEX,
|
||||||
} from "utils/DynamicBindingUtils";
|
} from "utils/DynamicBindingUtils";
|
||||||
import {
|
import {
|
||||||
getShouldFocusPropertyPath,
|
|
||||||
getWidgetPropsForPropertyName,
|
getWidgetPropsForPropertyName,
|
||||||
WidgetProperties,
|
WidgetProperties,
|
||||||
} from "selectors/propertyPaneSelectors";
|
} from "selectors/propertyPaneSelectors";
|
||||||
|
|
@ -55,8 +54,9 @@ import {
|
||||||
shouldFocusOnPropertyControl,
|
shouldFocusOnPropertyControl,
|
||||||
} from "utils/editorContextUtils";
|
} from "utils/editorContextUtils";
|
||||||
import PropertyPaneHelperText from "./PropertyPaneHelperText";
|
import PropertyPaneHelperText from "./PropertyPaneHelperText";
|
||||||
import { setFocusablePropertyPaneField } from "actions/propertyPaneActions";
|
|
||||||
import WidgetFactory from "utils/WidgetFactory";
|
import WidgetFactory from "utils/WidgetFactory";
|
||||||
|
import { getIsInputFieldFocused } from "selectors/editorContextSelectors";
|
||||||
|
import { setFocusableInputField } from "actions/editorContextActions";
|
||||||
|
|
||||||
type Props = PropertyPaneControlConfig & {
|
type Props = PropertyPaneControlConfig & {
|
||||||
panel: IPanelProps;
|
panel: IPanelProps;
|
||||||
|
|
@ -91,7 +91,7 @@ const PropertyControl = memo((props: Props) => {
|
||||||
const hasDispatchedPropertyFocus = useRef<boolean>(false);
|
const hasDispatchedPropertyFocus = useRef<boolean>(false);
|
||||||
const shouldFocusPropertyPath: boolean = useSelector(
|
const shouldFocusPropertyPath: boolean = useSelector(
|
||||||
(state: AppState) =>
|
(state: AppState) =>
|
||||||
getShouldFocusPropertyPath(
|
getIsInputFieldFocused(
|
||||||
state,
|
state,
|
||||||
dataTreePath,
|
dataTreePath,
|
||||||
hasDispatchedPropertyFocus.current,
|
hasDispatchedPropertyFocus.current,
|
||||||
|
|
@ -576,7 +576,7 @@ const PropertyControl = memo((props: Props) => {
|
||||||
if (!shouldFocusPropertyPath) {
|
if (!shouldFocusPropertyPath) {
|
||||||
hasDispatchedPropertyFocus.current = true;
|
hasDispatchedPropertyFocus.current = true;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
dispatch(setFocusablePropertyPaneField(dataTreePath));
|
dispatch(setFocusableInputField(dataTreePath));
|
||||||
}, 0);
|
}, 0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export type EditorContextState = {
|
||||||
entityCollapsibleFields: Record<string, boolean>;
|
entityCollapsibleFields: Record<string, boolean>;
|
||||||
subEntityCollapsibleFields: Record<string, boolean>;
|
subEntityCollapsibleFields: Record<string, boolean>;
|
||||||
explorerSwitchIndex: number;
|
explorerSwitchIndex: number;
|
||||||
focusableCodeEditor?: string;
|
focusedInputField?: string;
|
||||||
codeEditorHistory: Record<string, CodeEditorContext>;
|
codeEditorHistory: Record<string, CodeEditorContext>;
|
||||||
propertySectionState: Record<string, boolean>;
|
propertySectionState: Record<string, boolean>;
|
||||||
selectedPropertyTabIndex: number;
|
selectedPropertyTabIndex: number;
|
||||||
|
|
@ -61,14 +61,14 @@ export const isSubEntities = (name: string): boolean => {
|
||||||
* Context Reducer to store states of different components of editor
|
* Context Reducer to store states of different components of editor
|
||||||
*/
|
*/
|
||||||
export const editorContextReducer = createImmerReducer(initialState, {
|
export const editorContextReducer = createImmerReducer(initialState, {
|
||||||
[ReduxActionTypes.SET_FOCUSABLE_CODE_EDITOR_FIELD]: (
|
[ReduxActionTypes.SET_FOCUSABLE_INPUT_FIELD]: (
|
||||||
state: EditorContextState,
|
state: EditorContextState,
|
||||||
action: {
|
action: {
|
||||||
payload: { path: string };
|
payload: { path: string };
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
const { path } = action.payload;
|
const { path } = action.payload;
|
||||||
state.focusableCodeEditor = path;
|
state.focusedInputField = path;
|
||||||
},
|
},
|
||||||
[ReduxActionTypes.SET_CODE_EDITOR_CURSOR]: (
|
[ReduxActionTypes.SET_CODE_EDITOR_CURSOR]: (
|
||||||
state: EditorContextState,
|
state: EditorContextState,
|
||||||
|
|
|
||||||
|
|
@ -76,12 +76,6 @@ const propertyPaneReducer = createImmerReducer(initialState, {
|
||||||
) => {
|
) => {
|
||||||
state.width = action.payload;
|
state.width = action.payload;
|
||||||
},
|
},
|
||||||
[ReduxActionTypes.SET_FOCUSABLE_PROPERTY_FIELD]: (
|
|
||||||
state: PropertyPaneReduxState,
|
|
||||||
action: ReduxAction<{ path: string }>,
|
|
||||||
) => {
|
|
||||||
state.focusedProperty = action.payload.path;
|
|
||||||
},
|
|
||||||
[ReduxActionTypes.SET_SELECTED_PANEL_PROPERTY]: (
|
[ReduxActionTypes.SET_SELECTED_PANEL_PROPERTY]: (
|
||||||
state: PropertyPaneReduxState,
|
state: PropertyPaneReduxState,
|
||||||
action: {
|
action: {
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import { all, put, takeLatest } from "redux-saga/effects";
|
||||||
import {
|
import {
|
||||||
CodeEditorFocusState,
|
CodeEditorFocusState,
|
||||||
setCodeEditorCursorAction,
|
setCodeEditorCursorAction,
|
||||||
setFocusableCodeEditorField,
|
setFocusableInputField,
|
||||||
} from "actions/editorContextActions";
|
} from "actions/editorContextActions";
|
||||||
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
|
import { FocusEntity, identifyEntityFromPath } from "navigation/FocusEntity";
|
||||||
|
|
||||||
|
|
@ -28,10 +28,11 @@ function* setEditorFieldFocus(action: ReduxAction<CodeEditorFocusState>) {
|
||||||
window.location.pathname,
|
window.location.pathname,
|
||||||
window.location.hash,
|
window.location.hash,
|
||||||
);
|
);
|
||||||
|
const ignoredEntities = [FocusEntity.DATASOURCE];
|
||||||
|
|
||||||
if (key) {
|
if (key) {
|
||||||
if (entityInfo.entity !== FocusEntity.PROPERTY_PANE) {
|
if (!ignoredEntities.includes(entityInfo.entity)) {
|
||||||
yield put(setFocusableCodeEditorField(key));
|
yield put(setFocusableInputField(key));
|
||||||
}
|
}
|
||||||
yield put(setCodeEditorCursorAction(key, cursorPosition));
|
yield put(setCodeEditorCursorAction(key, cursorPosition));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ import { createSelector } from "reselect";
|
||||||
import { selectFeatureFlags } from "selectors/usersSelectors";
|
import { selectFeatureFlags } from "selectors/usersSelectors";
|
||||||
import FeatureFlags from "entities/FeatureFlags";
|
import FeatureFlags from "entities/FeatureFlags";
|
||||||
|
|
||||||
export const getFocusableCodeEditorField = (state: AppState) =>
|
export const getFocusableInputField = (state: AppState) =>
|
||||||
state.ui.editorContext.focusableCodeEditor;
|
state.ui.editorContext.focusedInputField;
|
||||||
|
|
||||||
export const getCodeEditorHistory = (state: AppState) =>
|
export const getCodeEditorHistory = (state: AppState) =>
|
||||||
state.ui.editorContext.codeEditorHistory;
|
state.ui.editorContext.codeEditorHistory;
|
||||||
|
|
@ -67,9 +67,9 @@ export const getSelectedPropertyTabIndex = createSelector(
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export const getIsCodeEditorFocused = createSelector(
|
export const getIsInputFieldFocused = createSelector(
|
||||||
[
|
[
|
||||||
getFocusableCodeEditorField,
|
getFocusableInputField,
|
||||||
selectFeatureFlags,
|
selectFeatureFlags,
|
||||||
(_state: AppState, key: string | undefined) => key,
|
(_state: AppState, key: string | undefined) => key,
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import { EVALUATION_PATH } from "utils/DynamicBindingUtils";
|
||||||
import { generateClassName } from "utils/generators";
|
import { generateClassName } from "utils/generators";
|
||||||
import { getWidgets } from "sagas/selectors";
|
import { getWidgets } from "sagas/selectors";
|
||||||
import { RegisteredWidgetFeatures } from "utils/WidgetFeatures";
|
import { RegisteredWidgetFeatures } from "utils/WidgetFeatures";
|
||||||
|
import { getFocusableInputField } from "./editorContextSelectors";
|
||||||
|
|
||||||
export type WidgetProperties = WidgetProps & {
|
export type WidgetProperties = WidgetProps & {
|
||||||
[EVALUATION_PATH]?: DataTreeEntity;
|
[EVALUATION_PATH]?: DataTreeEntity;
|
||||||
|
|
@ -266,18 +267,6 @@ export const getIsPropertyPaneVisible = createSelector(
|
||||||
export const getPropertyPaneWidth = (state: AppState) => {
|
export const getPropertyPaneWidth = (state: AppState) => {
|
||||||
return state.ui.propertyPane.width;
|
return state.ui.propertyPane.width;
|
||||||
};
|
};
|
||||||
export const getFocusablePropertyPaneField = (state: AppState) =>
|
|
||||||
state.ui.propertyPane.focusedProperty;
|
|
||||||
|
|
||||||
export const getShouldFocusPropertyPath = createSelector(
|
|
||||||
[
|
|
||||||
getFocusablePropertyPaneField,
|
|
||||||
(_state: AppState, key: string | undefined) => key,
|
|
||||||
],
|
|
||||||
(focusableField: string | undefined, key: string | undefined): boolean => {
|
|
||||||
return !!(key && focusableField === key);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const getSelectedPropertyPanelIndex = createSelector(
|
export const getSelectedPropertyPanelIndex = createSelector(
|
||||||
[
|
[
|
||||||
|
|
@ -296,7 +285,7 @@ export const getSelectedPropertyPanelIndex = createSelector(
|
||||||
|
|
||||||
export const getShouldFocusPropertySearch = createSelector(
|
export const getShouldFocusPropertySearch = createSelector(
|
||||||
getIsCurrentWidgetRecentlyAdded,
|
getIsCurrentWidgetRecentlyAdded,
|
||||||
getFocusablePropertyPaneField,
|
getFocusableInputField,
|
||||||
(
|
(
|
||||||
isCurrentWidgetRecentlyAdded: boolean,
|
isCurrentWidgetRecentlyAdded: boolean,
|
||||||
focusableField: string | undefined,
|
focusableField: string | undefined,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user