diff --git a/app/client/cypress/support/Pages/DataSources.ts b/app/client/cypress/support/Pages/DataSources.ts
index 35777482759..a961030d59f 100644
--- a/app/client/cypress/support/Pages/DataSources.ts
+++ b/app/client/cypress/support/Pages/DataSources.ts
@@ -194,7 +194,7 @@ export class DataSources {
_globalSearchInput = ".t--global-search-input";
_gsScopeDropdown =
"[data-testid^='datasourceStorages.'][data-testid$='.datasourceConfiguration.authentication.scopeString']";
- _gsScopeOptions = ".ads-v2-select__dropdown .rc-select-item-option";
+ _gsScopeOptions = ".ads-v2-radio-group";
_queryTimeout = "//input[@name='actionConfiguration.timeoutInMillisecond']";
_getStructureReq = "/api/v1/datasources/*/structure?ignoreCache=true";
_editDatasourceFromActiveTab = (dsName: string) =>
diff --git a/app/client/src/components/formControls/RadioButtonControl.test.tsx b/app/client/src/components/formControls/RadioButtonControl.test.tsx
new file mode 100644
index 00000000000..03077c379b1
--- /dev/null
+++ b/app/client/src/components/formControls/RadioButtonControl.test.tsx
@@ -0,0 +1,118 @@
+import React from "react";
+import RadioButtonControl from "./RadioButtonControl";
+import { render, screen } from "test/testUtils";
+import { Provider } from "react-redux";
+import { reduxForm } from "redux-form";
+import configureStore from "redux-mock-store";
+import "@testing-library/jest-dom";
+
+const mockStore = configureStore([]);
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+function TestForm(props: any) {
+ return
{props.children}
;
+}
+
+const ReduxFormDecorator = reduxForm({
+ form: "TestForm",
+})(TestForm);
+
+const mockOptions = [
+ { label: "Option 1", value: "option1", children: "Option 1" },
+ { label: "Option 2", value: "option2", children: "Option 2" },
+ { label: "Option 3", value: "option3", children: "Option 3" },
+];
+
+let radioButtonProps = {
+ options: mockOptions,
+ configProperty: "actionConfiguration.testPath",
+ controlType: "PROJECTION",
+ label: "Columns",
+ id: "column",
+ formName: "",
+ isValid: true,
+ initialValue: "option1",
+};
+
+describe("RadioButtonControl", () => {
+ const mockStoreInstance = mockStore();
+ let store: typeof mockStoreInstance;
+
+ beforeEach(() => {
+ store = mockStore();
+ });
+ it("should render RadioButtonControl and options properly", async () => {
+ render(
+
+
+
+
+ ,
+ );
+ const radioButton = (await screen.findByTestId(
+ "actionConfiguration.testPath",
+ )) as HTMLElement;
+
+ expect(radioButton).toBeInTheDocument();
+
+ const options = screen.getAllByRole("radio");
+
+ expect(options).toHaveLength(3);
+ });
+
+ it("should show the default selected option", async () => {
+ radioButtonProps = {
+ ...radioButtonProps,
+ };
+
+ render(
+
+
+
+
+ ,
+ );
+ const radioButton = (await screen.findByTestId(
+ "actionConfiguration.testPath",
+ )) as HTMLElement;
+
+ expect(radioButton).toBeInTheDocument();
+
+ const options = screen.getAllByRole("radio");
+
+ expect(options[0]).toBeChecked();
+ expect(options[1]).not.toBeChecked();
+ expect(options[2]).not.toBeChecked();
+ });
+
+ it("should select the option when clicked", async () => {
+ radioButtonProps = {
+ ...radioButtonProps,
+ };
+
+ render(
+
+
+
+
+ ,
+ );
+ const radioButton = (await screen.findByTestId(
+ "actionConfiguration.testPath",
+ )) as HTMLElement;
+
+ expect(radioButton).toBeInTheDocument();
+
+ const options = screen.getAllByRole("radio");
+
+ expect(options[0]).toBeChecked();
+ expect(options[1]).not.toBeChecked();
+ expect(options[2]).not.toBeChecked();
+
+ options[1].click();
+
+ expect(options[0]).not.toBeChecked();
+ expect(options[1]).toBeChecked();
+ expect(options[2]).not.toBeChecked();
+ });
+});
diff --git a/app/client/src/components/formControls/RadioButtonControl.tsx b/app/client/src/components/formControls/RadioButtonControl.tsx
new file mode 100644
index 00000000000..ecee054f58c
--- /dev/null
+++ b/app/client/src/components/formControls/RadioButtonControl.tsx
@@ -0,0 +1,70 @@
+import React from "react";
+import type { ControlProps } from "./BaseControl";
+import BaseControl from "./BaseControl";
+import type { ControlType } from "constants/PropertyControlConstants";
+import type { WrappedFieldInputProps, WrappedFieldMetaProps } from "redux-form";
+import { Field } from "redux-form";
+import { Radio, RadioGroup, type SelectOptionProps } from "@appsmith/ads";
+import styled from "styled-components";
+
+class RadioButtonControl extends BaseControl {
+ getControlType(): ControlType {
+ return "RADIO_BUTTON";
+ }
+ render() {
+ return (
+
+ );
+ }
+}
+
+type renderComponentProps = RadioButtonControlProps & {
+ input?: WrappedFieldInputProps;
+ meta?: WrappedFieldMetaProps;
+ options?: Array<{ label: string; value: string }>;
+};
+
+const StyledRadioGroup = styled(RadioGroup)({
+ display: "flex",
+ flexDirection: "column",
+ gap: "16px",
+ marginTop: "16px",
+});
+
+function renderComponent(props: renderComponentProps) {
+ const onChangeHandler = (value: string) => {
+ if (typeof props.input?.onChange === "function") {
+ props.input.onChange(value);
+ }
+ };
+
+ const options = props.options || [];
+ const defaultValue = props.initialValue as string;
+
+ return (
+
+ {options.map((option) => {
+ return (
+
+ {option.label}
+
+ );
+ })}
+
+ );
+}
+
+export interface RadioButtonControlProps extends ControlProps {
+ options: SelectOptionProps[];
+}
+
+export default RadioButtonControl;
diff --git a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx
index 414c920f5aa..94e34ba1c05 100644
--- a/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx
+++ b/app/client/src/pages/Editor/SaaSEditor/DatasourceForm.tsx
@@ -662,17 +662,6 @@ class DatasourceSaaSEditor extends JSONtoForm {
>
{(!viewMode || createFlow || isInsideReconnectModal) && (
<>
- {/* This adds information banner when creating google sheets datasource,
- this info banner explains why appsmith requires permissions from users google account */}
- {datasource && isGoogleSheetPlugin && createFlow ? (
-
- ) : null}
{/* This adds error banner for google sheets datasource if the datasource is unauthorised */}
{datasource &&
isGoogleSheetPlugin &&
@@ -688,6 +677,17 @@ class DatasourceSaaSEditor extends JSONtoForm {
? map(sections, this.renderMainSection)
: null}
{""}
+ {/* This adds information banner when creating google sheets datasource,
+ this info banner explains why appsmith requires permissions from users google account */}
+ {datasource && isGoogleSheetPlugin && createFlow ? (
+
+ ) : null}
>
)}
{viewMode &&
diff --git a/app/client/src/utils/formControl/FormControlRegistry.tsx b/app/client/src/utils/formControl/FormControlRegistry.tsx
index 90fe1623630..0779695fbdd 100644
--- a/app/client/src/utils/formControl/FormControlRegistry.tsx
+++ b/app/client/src/utils/formControl/FormControlRegistry.tsx
@@ -35,6 +35,8 @@ import FormTemplateControl from "components/formControls/FormTemplateControl";
import type { FormTemplateControlProps } from "components/formControls/FormTemplateControl";
import MultiFilePickerControl from "components/formControls/MultiFilePickerControl";
import type { MultipleFilePickerControlProps } from "components/formControls/MultiFilePickerControl";
+import type { RadioButtonControlProps } from "components/formControls/RadioButtonControl";
+import RadioButtonControl from "components/formControls/RadioButtonControl";
/**
* NOTE: If you are adding a component that uses FormControl
@@ -183,6 +185,11 @@ class FormControlRegistry {
},
},
);
+ FormControlFactory.registerControlBuilder(formControlTypes.RADIO_BUTTON, {
+ buildPropertyControl(controlProps: RadioButtonControlProps): JSX.Element {
+ return ;
+ },
+ });
}
}
diff --git a/app/client/src/utils/formControl/formControlTypes.ts b/app/client/src/utils/formControl/formControlTypes.ts
index 053f0d6f855..86242a50bdf 100644
--- a/app/client/src/utils/formControl/formControlTypes.ts
+++ b/app/client/src/utils/formControl/formControlTypes.ts
@@ -18,4 +18,5 @@ export default {
PROJECTION: "PROJECTION",
FORM_TEMPLATE: "FORM_TEMPLATE",
MULTIPLE_FILE_PICKER: "MULTIPLE_FILE_PICKER",
+ RADIO_BUTTON: "RADIO_BUTTON",
};
diff --git a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json
index d5f7709c310..8e9fe67783e 100644
--- a/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json
+++ b/app/server/appsmith-plugins/googleSheetsPlugin/src/main/resources/form.json
@@ -33,7 +33,7 @@
{
"label": "Permissions | Scope",
"configProperty": "datasourceConfiguration.authentication.scopeString",
- "controlType": "DROP_DOWN",
+ "controlType": "RADIO_BUTTON",
"options": [
{
"label": "Read / Write / Delete | Selected google sheets",