Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9e6417d
feat: show infinite scroll only when serverSidePagination is enabled
jacquesikot Mar 26, 2025
86bd4b0
feat: Add disabled state and disabled help text for property sections…
jacquesikot Mar 26, 2025
52dfadf
Merge branch 'release' of github.com:appsmithorg/appsmith into feat/a…
jacquesikot Mar 26, 2025
6132745
Revert "feat: show infinite scroll only when serverSidePagination is …
jacquesikot Mar 26, 2025
19c3620
refactor: Simplify PropertyControl component structure
jacquesikot Mar 26, 2025
7a3e6cc
test: add tests for disabled and disabledHelpText implementation
jacquesikot Mar 26, 2025
845406a
fix: disabled prop type mismatch between PropertyPaneControlConfig an…
jacquesikot Mar 26, 2025
5a57c17
refactor: Update imports and context usage in property controls to fi…
jacquesikot Mar 26, 2025
b1adca0
Merge branch 'release' of github.com:appsmithorg/appsmith into feat/a…
jacquesikot Mar 27, 2025
d8cba00
refactor: Clean up formatting and improve readability in property con…
jacquesikot Mar 27, 2025
14db8bb
refactor: Update imports in PropertySection component
jacquesikot Mar 27, 2025
3536352
fix: lint error
jacquesikot Mar 27, 2025
2a75ea6
fix: lint error
jacquesikot Mar 27, 2025
864f329
refactor: Rename isReadOnly to isControlDisabled and update type defi…
jacquesikot Mar 31, 2025
007a525
refactor: Update type definitions for hidden and disabled properties …
jacquesikot Mar 31, 2025
5a68737
refactor: Update type definitions for hidden and disabled properties …
jacquesikot Mar 31, 2025
f79ccfd
refactor: Update type definitions for hidden and disabled properties …
jacquesikot Mar 31, 2025
d4f7b64
refactor: Update type definitions for hidden and disabled properties …
jacquesikot Mar 31, 2025
aa2b8fc
refactor: Update hidden and disabled property type definitions in Pro…
jacquesikot Mar 31, 2025
2164882
refactor: Reorganize imports in PropertyControl component
jacquesikot Mar 31, 2025
17a09a3
Merge branch 'release' of github.com:appsmithorg/appsmith into feat/a…
jacquesikot Apr 1, 2025
7b5cd76
refactor: rename disabled property to shouldDisableSection in propert…
jacquesikot Apr 1, 2025
efa3347
refactor: remove disabled properties from pagination section in Table…
jacquesikot Apr 1, 2025
1e656cf
refactor: sort props alphabetically
jacquesikot Apr 1, 2025
08429fe
refactor: reorder props in CodeEditorControl component
jacquesikot Apr 1, 2025
285d46d
refactor: remove unused marking prop from CodeEditorControl component
jacquesikot Apr 1, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 25 additions & 19 deletions app/client/src/components/propertyControls/CodeEditorControl.tsx
Original file line number Diff line number Diff line change
@@ -1,50 +1,56 @@
import type { ChangeEvent } from "react";
import React from "react";
import type { ControlProps } from "./BaseControl";
import BaseControl from "./BaseControl";
import type { EventOrValueHandler } from "redux-form";
import { slashCommandHintHelper } from "components/editorComponents/CodeEditor/commandsHelper";
import {
EditorModes,
EditorSize,
EditorTheme,
TabBehaviour,
} from "components/editorComponents/CodeEditor/EditorConfig";
import LazyCodeEditor from "components/editorComponents/LazyCodeEditor";
import { bindingHintHelper } from "components/editorComponents/CodeEditor/hintHelpers";
import { slashCommandHintHelper } from "components/editorComponents/CodeEditor/commandsHelper";
import type { EditorProps } from "components/editorComponents/CodeEditor";
import LazyCodeEditor from "components/editorComponents/LazyCodeEditor";
import type { ChangeEvent } from "react";
import React from "react";
import type { EventOrValueHandler } from "redux-form";
import type { ControlProps } from "./BaseControl";
import BaseControl from "./BaseControl";

class CodeEditorControl extends BaseControl<ControlProps> {
render() {
const {
controlConfig,
dataTreePath,
disabled,
evaluatedValue,
expected,
propertyValue,
useValidationMessage,
} = this.props;

const props: Partial<ControlProps> = {};

if (dataTreePath) props.dataTreePath = dataTreePath;

if (evaluatedValue) props.evaluatedValue = evaluatedValue;

if (expected) props.expected = expected;

// PropertyPaneControlConfig's disabled is a function (props: any, propertyPath: string) => boolean
// while LazyCodeEditor expects a boolean. Convert function to boolean result.
const isReadOnly = typeof disabled === "function"
? disabled(this.props.widgetProperties, this.props.propertyName)
: !!disabled;

const maxHeight = controlConfig?.maxHeight ?
String(controlConfig.maxHeight) : undefined;

return (
<LazyCodeEditor
additionalDynamicData={this.props.additionalAutoComplete}
dataTreePath={dataTreePath}
evaluatedValue={evaluatedValue}
expected={expected}
hinting={[bindingHintHelper, slashCommandHintHelper]}
input={{ value: propertyValue, onChange: this.onChange }}
maxHeight={controlConfig?.maxHeight as EditorProps["maxHeight"]}
isReadOnly={isReadOnly}
marking={[]}
Comment thread
rahulbarwal marked this conversation as resolved.
Outdated
maxHeight={maxHeight}
mode={EditorModes.TEXT_WITH_BINDING}
positionCursorInsideBinding
size={EditorSize.EXTENDED}
tabBehaviour={TabBehaviour.INDENT}
theme={this.props.theme}
theme={EditorTheme.LIGHT}
useValidationMessage={useValidationMessage}
{...props}
AIAssisted
/>
);
Expand Down
26 changes: 26 additions & 0 deletions app/client/src/constants/PropertyControlConstants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ export interface PropertyPaneSectionConfig {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
hidden?: (props: any, propertyPath: string) => boolean;
/**
* @param props - Current widget properties
* @param propertyPath - Path to the widget property
* @returns - True if the section should be disabled, false otherwise
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove this? Let's not use any; you can prefer using unknown but since these are WidgetProps, do you think we can use that without any cyclic dependency?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tried widget props and I still get a lot of errors on CI - build failure due to type check.

disabled?: (props: any, propertyPath: string) => boolean;
/**
* Help text to show when section is disabled.
* Appears as a tooltip when hovering over the disabled section.
*/
disabledHelpText?: string;
/**
* when true, the section will be open by default.
* Note: Seems like this is not used anywhere.
Expand Down Expand Up @@ -205,6 +217,20 @@ export interface PropertyPaneControlConfig {
// TODO: Fix this the next time the file is edited
// eslint-disable-next-line @typescript-eslint/no-explicit-any
hidden?: (props: any, propertyPath: string) => boolean;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ› οΈ Refactor suggestion

Update this property to use more specific typing.

Similar to line 53, this property should be updated from any to Record<string, unknown> for consistency across the interface and improved type safety.

-  // TODO: Fix this the next time the file is edited
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  hidden?: (props: any, propertyPath: string) => boolean;
+  hidden?: (props: Record<string, unknown>, propertyPath: string) => boolean;

Committable suggestion skipped: line range outside the PR's diff.

/**
* callback function to determine if the property should be disabled.

* @param props - Current widget properties
* @param propertyPath - Path to the widget property
* @returns - True if the property should be disabled, false otherwise
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
disabled?: (props: any, propertyPath: string) => boolean;
/**
* Help text to show when property is disabled.
* Appears as a tooltip when hovering over the disabled property.
*/
disabledHelpText?: string;
/**
* If true, the property is hidden.
* Note: hidden and invisible do the same thing but differently. hidden uses a callback to determine if the property should be hidden.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React from "react";
import { render } from "@testing-library/react";
import { EditorTheme } from "components/editorComponents/CodeEditor/EditorConfig";
import type { IPanelProps } from "@blueprintjs/core";

const MockPropertyControl = (props: any) => {
const isDisabled = props.disabled ? props.disabled(props.widgetProperties, props.propertyName) : false;

return (
<div data-testid="t--property-control-wrapper" className={isDisabled ? "cursor-not-allowed opacity-50" : ""}>
<label>{props.label}</label>
<input
type="text"
role="textbox"
disabled={isDisabled}
data-testid="property-input"
/>
{isDisabled && props.disabledHelpText && (
<div data-testid="disabled-help-text">{props.disabledHelpText}</div>
)}
</div>
);
};

jest.mock("./PropertyControl", () => (props: any) => <MockPropertyControl {...props} />);

describe("PropertyControl", () => {
const mockPanel: IPanelProps = {
closePanel: jest.fn(),
openPanel: jest.fn(),
};

const defaultProps = {
propertyName: "testProperty",
label: "Test Label",
controlType: "INPUT_TEXT",
isBindProperty: true,
isTriggerProperty: false,
panel: mockPanel,
theme: EditorTheme.LIGHT,
isSearchResult: false,
widgetProperties: {
widgetId: "test-widget",
widgetName: "TestWidget",
type: "CONTAINER_WIDGET",
testProperty: "test value"
}
};

it("should render property control normally when not disabled", () => {
const PropertyControl = require("./PropertyControl");
const { getByTestId } = render(<PropertyControl {...defaultProps} />);

expect((getByTestId("property-input") as HTMLInputElement).disabled).toBe(false);
expect(getByTestId("t--property-control-wrapper").className).toBe("");
});

it("should render disabled property control when disabled prop is true", () => {
const PropertyControl = require("./PropertyControl");
const disabledProps = {
...defaultProps,
disabled: () => true,
};

const { getByTestId } = render(<PropertyControl {...disabledProps} />);

const wrapper = getByTestId("t--property-control-wrapper");
expect(wrapper.classList.contains("cursor-not-allowed")).toBe(true);
expect(wrapper.classList.contains("opacity-50")).toBe(true);
expect((getByTestId("property-input") as HTMLInputElement).disabled).toBe(true);
});

it("should show disabled help text when property is disabled", () => {
const PropertyControl = require("./PropertyControl");
const disabledProps = {
...defaultProps,
disabled: () => true,
disabledHelpText: "This property is disabled because...",
};

const { getByTestId } = render(<PropertyControl {...disabledProps} />);

expect(getByTestId("disabled-help-text")).toBeTruthy();
expect(getByTestId("disabled-help-text").textContent).toBe("This property is disabled because...");
});

it("should not show disabled help text when property is not disabled", () => {
const PropertyControl = require("./PropertyControl");
const props = {
...defaultProps,
disabled: () => false,
disabledHelpText: "This property is disabled because...",
};

const { queryByTestId } = render(<PropertyControl {...props} />);

expect(queryByTestId("disabled-help-text")).toBeFalsy();
});
});
Loading