diff --git a/.env.example b/.env.example index 2a18278f83..2a2b1e90ac 100644 --- a/.env.example +++ b/.env.example @@ -15,6 +15,10 @@ APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET= APPSMITH_OAUTH2_GITHUB_CLIENT_ID= APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET= +# Form Login/Signup +APPSMITH_FORM_LOGIN_DISABLED= +APPSMITH_SIGNUP_DISABLED= + # Segment APPSMITH_SEGMENT_KEY= diff --git a/app/client/src/ce/configs/index.ts b/app/client/src/ce/configs/index.ts index 6a67ca775f..5200a0d269 100644 --- a/app/client/src/ce/configs/index.ts +++ b/app/client/src/ce/configs/index.ts @@ -71,8 +71,12 @@ export const getConfigsFromEnvVars = (): INJECTED_CONFIGS => { enableGithubOAuth: process.env.REACT_APP_OAUTH2_GITHUB_CLIENT_ID ? process.env.REACT_APP_OAUTH2_GITHUB_CLIENT_ID.length > 0 : false, - disableLoginForm: !!process.env.APPSMITH_FORM_LOGIN_DISABLED, - disableSignup: !!process.env.APPSMITH_SIGNUP_DISABLED, + disableLoginForm: process.env.APPSMITH_FORM_LOGIN_DISABLED + ? process.env.APPSMITH_FORM_LOGIN_DISABLED.length > 0 + : false, + disableSignup: process.env.APPSMITH_SIGNUP_DISABLED + ? process.env.APPSMITH_SIGNUP_DISABLED.length > 0 + : false, segment: { apiKey: process.env.REACT_APP_SEGMENT_KEY || "", ceKey: process.env.REACT_APP_SEGMENT_CE_KEY || "", diff --git a/app/client/src/ce/constants/messages.ts b/app/client/src/ce/constants/messages.ts index 44c80e3143..412217b7b3 100644 --- a/app/client/src/ce/constants/messages.ts +++ b/app/client/src/ce/constants/messages.ts @@ -633,6 +633,11 @@ export const CANNOT_PULL_WITH_LOCAL_UNCOMMITTED_CHANGES = () => export const CANNOT_MERGE_DUE_TO_UNCOMMITTED_CHANGES = () => "Your current branch has uncommitted changes. Please commit before proceeding to merge"; +export const DISCONNECT_SERVICE_SUBHEADER = () => + "Changes to this section can disrupt user authentication. Proceed with caution."; +export const DISCONNECT_SERVICE_WARNING = () => + "will be removed as primary method of authentication"; + export const DISCONNECT_EXISTING_REPOSITORIES = () => "Disconnect existing Repositories"; export const DISCONNECT_EXISTING_REPOSITORIES_INFO = () => @@ -1034,3 +1039,6 @@ export const CONTEXT_DELETE = () => "Delete"; export const CONTEXT_NO_PAGE = () => "No pages"; export const IMAGE_LOAD_ERROR = () => "Unable to display the image"; + +export const REDIRECT_URL_TOOLTIP = () => + "This URL will be used while configuring your Identity Provider's Callback/Redirect URL"; diff --git a/app/client/src/ce/pages/AdminSettings/config/authentication/index.tsx b/app/client/src/ce/pages/AdminSettings/config/authentication/index.tsx index 53ebf2c542..951d865820 100644 --- a/app/client/src/ce/pages/AdminSettings/config/authentication/index.tsx +++ b/app/client/src/ce/pages/AdminSettings/config/authentication/index.tsx @@ -2,6 +2,7 @@ import React from "react"; import { GOOGLE_SIGNUP_SETUP_DOC, GITHUB_SIGNUP_SETUP_DOC, + SIGNUP_RESTRICTION_DOC, } from "constants/ThirdPartyConstants"; import { SettingCategories, @@ -28,6 +29,7 @@ const Form_Auth: AdminConfigType = { title: "Form Login", subText: "Enable your organization to sign in with Appsmith Form.", canSave: true, + isConnected: false, settings: [ { id: "APPSMITH_FORM_LOGIN_DISABLED", @@ -37,9 +39,9 @@ const Form_Auth: AdminConfigType = { label: "Form Login Option", toggleText: (value: boolean) => { if (value) { - return "Enable form login/signup"; + return "Disabled"; } else { - return " Disable form login/signup"; + return " Enabled"; } }, }, @@ -51,12 +53,22 @@ const Form_Auth: AdminConfigType = { label: "Signup", toggleText: (value: boolean) => { if (value) { - return "Allow invited users to signup"; + return "Allow only invited users to signup"; } else { return " Allow all users to signup"; } }, }, + { + id: "APPSMITH_FORM_CALLOUT_BANNER", + category: SettingCategories.FORM_AUTH, + subCategory: "form signup", + controlType: SettingTypes.LINK, + label: + "User emails are not verified. This can lead to a breach in your application.", + url: SIGNUP_RESTRICTION_DOC, + calloutType: "Warning", + }, ], }; @@ -66,6 +78,7 @@ const Google_Auth: AdminConfigType = { title: "Google Authentication", subText: "Enable your organization to sign in with Google (OAuth).", canSave: true, + isConnected: enableGoogleOAuth, settings: [ { id: "APPSMITH_OAUTH2_GOOGLE_READ_MORE", @@ -110,6 +123,7 @@ const Github_Auth: AdminConfigType = { subText: "Enable your organization to sign in with Github SAML single sign-on (SSO).", canSave: true, + isConnected: enableGithubOAuth, settings: [ { id: "APPSMITH_OAUTH2_GITHUB_READ_MORE", diff --git a/app/client/src/ce/pages/AdminSettings/config/types.ts b/app/client/src/ce/pages/AdminSettings/config/types.ts index 1868b97769..859a8776ab 100644 --- a/app/client/src/ce/pages/AdminSettings/config/types.ts +++ b/app/client/src/ce/pages/AdminSettings/config/types.ts @@ -10,6 +10,9 @@ export enum SettingTypes { GROUP = "GROUP", TEXT = "TEXT", PAGE = "PAGE", + UNEDITABLEFIELD = "UNEDITABLEFIELD", + ACCORDION = "ACCORDION", + TAGINPUT = "TAGINPUT", } export enum SettingSubtype { @@ -44,12 +47,15 @@ export interface Setting { isVisible?: (values: Record) => boolean; isHidden?: boolean; isDisabled?: (values: Record) => boolean; + calloutType?: "Info" | "Warning"; + advanced?: Setting[]; } export interface Category { title: string; slug: string; subText?: string; + isConnected?: boolean; children?: Category[]; } @@ -74,4 +80,5 @@ export type AdminConfigType = { component?: React.ElementType; children?: AdminConfigType[]; canSave: boolean; + isConnected?: boolean; }; diff --git a/app/client/src/ce/utils/adminSettingsHelpers.ts b/app/client/src/ce/utils/adminSettingsHelpers.ts new file mode 100644 index 0000000000..6a83b7000b --- /dev/null +++ b/app/client/src/ce/utils/adminSettingsHelpers.ts @@ -0,0 +1,28 @@ +import { getAppsmithConfigs } from "@appsmith/configs"; +const { + disableLoginForm, + enableGithubOAuth, + enableGoogleOAuth, +} = getAppsmithConfigs(); + +export const connectedMethods = [ + enableGoogleOAuth, + enableGithubOAuth, + !disableLoginForm, +].filter(Boolean); + +export const saveAllowed = (settings: any) => { + if ( + connectedMethods.length >= 2 || + (connectedMethods.length === 1 && + ((!("APPSMITH_FORM_LOGIN_DISABLED" in settings) && !disableLoginForm) || + (settings["APPSMITH_OAUTH2_GOOGLE_CLIENT_ID"] !== "" && + enableGoogleOAuth) || + (settings["APPSMITH_OAUTH2_GITHUB_CLIENT_ID"] !== "" && + enableGithubOAuth))) + ) { + return true; + } else { + return false; + } +}; diff --git a/app/client/src/components/ads/TagInputComponent.tsx b/app/client/src/components/ads/TagInputComponent.tsx index 8dae2ee12d..6b71360c80 100644 --- a/app/client/src/components/ads/TagInputComponent.tsx +++ b/app/client/src/components/ads/TagInputComponent.tsx @@ -8,6 +8,7 @@ import { } from "@appsmith/constants/messages"; import { isEmail } from "utils/formhelpers"; import { Colors } from "constants/Colors"; + const TagInputWrapper = styled.div<{ intent?: Intent }>` margin-right: 8px; @@ -57,7 +58,7 @@ type TagInputProps = { /** Intent of the tags, which defines their color */ intent?: Intent; hasError?: boolean; - customError: (values: any) => void; + customError?: (values: any) => void; }; /** @@ -89,9 +90,9 @@ function TagInputComponent(props: TagInputProps) { error = createMessage(INVITE_USERS_VALIDATION_EMAIL_LIST); } }); - props.customError(error); + props.customError?.(error); } else { - props.customError(""); + props.customError?.(""); } }; @@ -99,7 +100,7 @@ function TagInputComponent(props: TagInputProps) { setValues(newValues); props.input.onChange && props.input.onChange(newValues.filter(Boolean).join(",")); - validateEmail(newValues); + props.type === "email" && validateEmail(newValues); }; const onTagsChange = (values: React.ReactNode[]) => { diff --git a/app/client/src/components/ads/TextInput.tsx b/app/client/src/components/ads/TextInput.tsx index ab371f8702..4758f25e6d 100644 --- a/app/client/src/components/ads/TextInput.tsx +++ b/app/client/src/components/ads/TextInput.tsx @@ -74,6 +74,7 @@ export type TextInputProps = CommonComponentProps & { trimValue?: boolean; $padding?: string; useTextArea?: boolean; + isCopy?: boolean; }; type boxReturnType = { diff --git a/app/client/src/components/ads/formFields/RedirectUrlForm.tsx b/app/client/src/components/ads/formFields/RedirectUrlForm.tsx new file mode 100644 index 0000000000..960904ed09 --- /dev/null +++ b/app/client/src/components/ads/formFields/RedirectUrlForm.tsx @@ -0,0 +1,107 @@ +import React, { useEffect } from "react"; +import { InjectedFormProps, reduxForm } from "redux-form"; +import { HelpIcons } from "icons/HelpIcons"; +import UneditableField from "components/ads/formFields/UneditableField"; +import styled from "styled-components"; +import copy from "copy-to-clipboard"; +import { Toaster } from "components/ads/Toast"; +import { Variant } from "components/ads/common"; +import AnalyticsUtil from "utils/AnalyticsUtil"; +import TooltipComponent from "../Tooltip"; +import { Position } from "@blueprintjs/core"; +import { + createMessage, + REDIRECT_URL_TOOLTIP, +} from "@appsmith/constants/messages"; + +const HelpIcon = HelpIcons.HELP_ICON; + +const Wrapper = styled.div` + margin: 24px 0; +`; + +export const BodyContainer = styled.div` + width: 100%; + padding: 0 0 16px; +`; + +const HeaderWrapper = styled.div` + display: flex; + align-items: center; + margin-bottom: 8px; + .help-icon { + margin-left: 4px; + cursor: pointer; + svg { + border-radius: 50%; + border: 1px solid #858282; + padding: 1px; + } + } +`; + +export const HeaderSecondary = styled.h3` + font-size: 20px; + font-style: normal; + font-weight: 500; + line-height: 24px; + letter-spacing: -0.23999999463558197px; + text-align: left; +`; + +function RedirectUrlForm( + props: InjectedFormProps & { value: string; helpText?: string }, +) { + useEffect(() => { + props.initialize({ + "redirect-url-form": `${window.location.origin}${props.value}`, + }); + }, []); + + const handleCopy = (value: string) => { + copy(value); + Toaster.show({ + text: "Redirect URL copied to clipboard", + variant: Variant.success, + }); + AnalyticsUtil.logEvent("REDIRECT_URL_COPIED", { snippet: value }); + }; + + return ( + + + Redirect URL + + + + + + + + + ); +} + +export const RedirectUrlReduxForm = reduxForm({ + form: "Redirect URL", + touchOnBlur: true, +})(RedirectUrlForm); diff --git a/app/client/src/components/ads/formFields/UneditableField.tsx b/app/client/src/components/ads/formFields/UneditableField.tsx new file mode 100644 index 0000000000..0b67a3fc5a --- /dev/null +++ b/app/client/src/components/ads/formFields/UneditableField.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { + Field, + WrappedFieldMetaProps, + WrappedFieldInputProps, +} from "redux-form"; +import InputComponent, { InputType } from "../TextInput"; +import { Intent } from "constants/DefaultTheme"; +import { Colors } from "constants/Colors"; +import styled from "styled-components"; +import { ReactComponent as CopyIcon } from "assets/icons/menu/copy-snippet.svg"; + +const Label = styled.div` + font-size: 14px; + margin: 8px 0; + color: ${Colors.CHARCOAL}; +`; + +const InputCopyWrapper = styled.div` + display: flex; + align-items: center; + + svg { + margin-left: 10px; + cursor: pointer; + } +`; + +const renderComponent = ( + componentProps: FormTextFieldProps & { + meta: Partial; + input: Partial; + }, +) => { + return ( + <> + {componentProps.label && } + + + {componentProps.iscopy === "true" && ( + + componentProps.handleCopy(componentProps.input.value) + } + width={16} + /> + )} + + + ); +}; + +export type FormTextFieldProps = { + name: string; + type?: InputType; + label?: string; + intent?: Intent; + disabled?: boolean; + autoFocus?: boolean; + value?: string; + helperText?: string; + iscopy?: string; + handleCopy: (value: string) => void; +}; + +function UneditableField(props: FormTextFieldProps) { + return ; +} + +export default UneditableField; diff --git a/app/client/src/constants/ThirdPartyConstants.tsx b/app/client/src/constants/ThirdPartyConstants.tsx index 6c7d1f0007..7bc2ad7986 100644 --- a/app/client/src/constants/ThirdPartyConstants.tsx +++ b/app/client/src/constants/ThirdPartyConstants.tsx @@ -15,3 +15,5 @@ export const GITHUB_SIGNUP_SETUP_DOC = "https://docs.appsmith.com/setup/instance-configuration/github-login"; export const EMAIL_SETUP_DOC = "https://docs.appsmith.com/setup/instance-configuration/email"; +export const SIGNUP_RESTRICTION_DOC = + "https://docs.appsmith.com/setup/instance-configuration/disable-user-signup#disable-sign-up"; diff --git a/app/client/src/ee/utils/adminSettingsHelpers.ts b/app/client/src/ee/utils/adminSettingsHelpers.ts new file mode 100644 index 0000000000..04d5f40432 --- /dev/null +++ b/app/client/src/ee/utils/adminSettingsHelpers.ts @@ -0,0 +1 @@ +export * from "ce/utils/adminSettingsHelpers"; diff --git a/app/client/src/pages/Settings/FormGroup/Accordion.tsx b/app/client/src/pages/Settings/FormGroup/Accordion.tsx new file mode 100644 index 0000000000..fd9717866f --- /dev/null +++ b/app/client/src/pages/Settings/FormGroup/Accordion.tsx @@ -0,0 +1,86 @@ +import React, { useState } from "react"; +import styled from "styled-components"; + +import { Setting } from "@appsmith/pages/AdminSettings/config/types"; +import { createMessage } from "@appsmith//constants/messages"; +import { StyledLabel } from "./Common"; +import Group from "./group"; +import { Icon, IconSize } from "components/ads"; + +const AccordionWrapper = styled.div` + margin-top: 40px; + max-width: 634px; +`; + +const AccordionHeader = styled(StyledLabel)` + text-transform: capitalize; + margin-bottom: ${(props) => props.theme.spaces[9]}px; + font-size: 20px; + font-weight: 500; + cursor: pointer; + display: flex; + justify-content: space-between; + align-items: center; +`; + +const AccordionBody = styled.div` + & .hide { + display: none; + } + & .callout-link { + > div { + margin-top: 0px; + } + } +`; + +const Line = styled.hr` + display: block; + height: 1px; + border: 0; + border-top: 1px solid #DFDFDF; + margin: 0 16px; + flex: 1 0 auto; +} +`; + +type AccordionProps = { + label?: string; + settings?: Setting[]; + isHidden?: boolean; + category?: string; + subCategory?: string; +}; + +export default function Accordion({ + category, + label, + settings, + subCategory, +}: AccordionProps) { + const [isOpen, setIsOpen] = useState(false); + + return ( + + {label && ( + setIsOpen(!isOpen)}> + {createMessage(() => label)} + + + + )} + {isOpen && ( + + + + )} + + ); +} diff --git a/app/client/src/pages/Settings/FormGroup/Common.tsx b/app/client/src/pages/Settings/FormGroup/Common.tsx index 7262721df0..fb2b2e6398 100644 --- a/app/client/src/pages/Settings/FormGroup/Common.tsx +++ b/app/client/src/pages/Settings/FormGroup/Common.tsx @@ -18,7 +18,7 @@ const StyledIcon = styled(Icon)` `; export const StyledFormGroup = styled.div` - width: 634px; + width: 40rem; margin-bottom: ${(props) => props.theme.spaces[7]}px; & span.bp3-popover-target { display: inline-block; diff --git a/app/client/src/pages/Settings/FormGroup/TagInputField.tsx b/app/client/src/pages/Settings/FormGroup/TagInputField.tsx new file mode 100644 index 0000000000..6ecbc02aad --- /dev/null +++ b/app/client/src/pages/Settings/FormGroup/TagInputField.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { + Field, + WrappedFieldMetaProps, + WrappedFieldInputProps, +} from "redux-form"; +import TagInputComponent from "components/ads/TagInputComponent"; +import { FormGroup } from "./Common"; +import { Intent } from "constants/DefaultTheme"; +import { Setting } from "@appsmith/pages/AdminSettings/config/types"; + +const renderComponent = ( + componentProps: TagListFieldProps & { + meta: Partial; + input: Partial; + }, +) => { + const setting = componentProps.setting; + return ( + + + + ); +}; + +type TagListFieldProps = { + name: string; + placeholder: string; + type: string; + label?: string; + intent: Intent; + setting: Setting; + customError?: (err: string) => void; +}; + +function TagInputField(props: TagListFieldProps) { + return ; +} + +export default TagInputField; diff --git a/app/client/src/pages/Settings/FormGroup/TextInput.tsx b/app/client/src/pages/Settings/FormGroup/TextInput.tsx index c468da8f91..ae37172c6c 100644 --- a/app/client/src/pages/Settings/FormGroup/TextInput.tsx +++ b/app/client/src/pages/Settings/FormGroup/TextInput.tsx @@ -10,7 +10,7 @@ export default function TextInput({ setting }: SettingComponentProps) { setting={setting} > setting.placeholder || "")} type={setting.controlSubType} /> diff --git a/app/client/src/pages/Settings/FormGroup/group.tsx b/app/client/src/pages/Settings/FormGroup/group.tsx index 4f94cb25e7..313f755d61 100644 --- a/app/client/src/pages/Settings/FormGroup/group.tsx +++ b/app/client/src/pages/Settings/FormGroup/group.tsx @@ -14,6 +14,11 @@ import { SETTINGS_FORM_NAME } from "constants/forms"; import { useSelector } from "store"; import { createMessage } from "@appsmith/constants/messages"; import { Callout } from "components/ads/CalloutV2"; +import { RedirectUrlReduxForm } from "components/ads/formFields/RedirectUrlForm"; +import Accordion from "./Accordion"; +import TagInputField from "./TagInputField"; +import { Classes } from "@blueprintjs/core"; +import { Colors } from "constants/Colors"; type GroupProps = { name?: string; @@ -43,11 +48,33 @@ const GroupBody = styled.div` display: none; } & .callout-link { - max-width: 634px; > div { margin-top: 0px; } } + & .tag-input { + .t--admin-settings-tag-input { + label { + + div { + margin: 0; + } + } + .${Classes.TAG_INPUT}, .${Classes.TAG_INPUT}.${Classes.ACTIVE} { + border: 1.2px solid ${Colors.ALTO2}; + box-shadow: none; + .bp3-tag { + background: #f8f8f8; + color: #000; + svg:hover { + cursor: pointer; + path { + fill: currentColor; + } + } + } + } + } + } `; const formValuesSelector = getFormValues(SETTINGS_FORM_NAME); @@ -79,7 +106,7 @@ export default function Group({
@@ -89,7 +116,7 @@ export default function Group({
@@ -101,13 +128,13 @@ export default function Group({ setting.isHidden ? "hide" : "callout-link" } t--read-more-link`} data-testid="admin-settings-group-link" - key={setting.name} + key={setting.name || setting.id} > setting.label || "")} - type="Info" + type={setting.calloutType || "Info"} url={setting.url} /> @@ -117,7 +144,7 @@ export default function Group({
@@ -127,7 +154,7 @@ export default function Group({
@@ -137,7 +164,7 @@ export default function Group({
); + case SettingTypes.UNEDITABLEFIELD: + return ( +
+ +
+ ); + case SettingTypes.TAGINPUT: + return ( +
+ +
+ ); + case SettingTypes.ACCORDION: + return ( +
+ +
+ ); } })} diff --git a/app/client/src/pages/Settings/SettingsForm.tsx b/app/client/src/pages/Settings/SettingsForm.tsx index 8c31baf727..1fa91b547e 100644 --- a/app/client/src/pages/Settings/SettingsForm.tsx +++ b/app/client/src/pages/Settings/SettingsForm.tsx @@ -18,7 +18,21 @@ import Group from "./FormGroup/group"; import RestartBanner from "./RestartBanner"; import AdminConfig from "./config"; import SaveAdminSettings from "./SaveSettings"; -import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types"; +import { + SettingTypes, + Setting, +} from "@appsmith/pages/AdminSettings/config/types"; +import { DisconnectService } from "./DisconnectService"; +import { + createMessage, + DISCONNECT_SERVICE_SUBHEADER, + DISCONNECT_SERVICE_WARNING, +} from "@appsmith/constants/messages"; +import { Toaster, Variant } from "components/ads"; +import { + connectedMethods, + saveAllowed, +} from "@appsmith/utils/adminSettingsHelpers"; const Wrapper = styled.div` flex-basis: calc(100% - ${(props) => props.theme.homePage.leftPane.width}px); @@ -28,7 +42,9 @@ const Wrapper = styled.div` overflow: auto; `; -const SettingsFormWrapper = styled.div``; +const SettingsFormWrapper = styled.div` + max-width: 40rem; +`; export const BottomSpace = styled.div` height: ${(props) => props.theme.settings.footerHeight + 20}px; @@ -79,9 +95,16 @@ export function SettingsForm( const isSavable = AdminConfig.savableCategories.includes( subCategory ?? category, ); + const pageTitle = getSettingLabel( + details?.title || (subCategory ?? category), + ); const onSave = () => { - dispatch(saveSettings(props.settings)); + if (saveAllowed(props.settings)) { + dispatch(saveSettings(props.settings)); + } else { + saveBlocked(); + } }; const onClear = () => { @@ -90,13 +113,6 @@ export function SettingsForm( if (setting && setting.controlType == SettingTypes.TOGGLE) { props.settingsConfig[settingName] = props.settingsConfig[settingName].toString() == "true"; - - if ( - typeof props.settingsConfig["APPSMITH_SIGNUP_DISABLED"] === - "undefined" - ) { - props.settingsConfig["APPSMITH_SIGNUP_DISABLED"] = true; - } } }); props.initialize(props.settingsConfig); @@ -111,13 +127,32 @@ export function SettingsForm( }); }, []); + const saveBlocked = () => { + Toaster.show({ + text: "Cannot disconnect the only connected authentication method.", + variant: Variant.danger, + }); + }; + + const disconnect = (currentSettings: AdminConfig) => { + const updatedSettings: any = {}; + if (connectedMethods.length >= 2) { + _.forEach(currentSettings, (setting: Setting) => { + if (!setting.isHidden && setting.controlType !== SettingTypes.LINK) { + updatedSettings[setting.id] = ""; + } + }); + dispatch(saveSettings(updatedSettings)); + } else { + saveBlocked(); + } + }; + return ( - - {getSettingLabel(details?.title || (subCategory ?? category))} - + {pageTitle} {details?.subText && ( {details.subText} )} @@ -136,6 +171,15 @@ export function SettingsForm( valid={props.valid} /> )} + {details?.isConnected && ( + disconnect(settings)} + subHeader={createMessage(DISCONNECT_SERVICE_SUBHEADER)} + warning={`${pageTitle} ${createMessage( + DISCONNECT_SERVICE_WARNING, + )}`} + /> + )} {props.showReleaseNotes && ( diff --git a/app/client/src/pages/Settings/config/ConfigFactory.ts b/app/client/src/pages/Settings/config/ConfigFactory.ts index 592f66bd32..9fda584ade 100644 --- a/app/client/src/pages/Settings/config/ConfigFactory.ts +++ b/app/client/src/pages/Settings/config/ConfigFactory.ts @@ -20,6 +20,12 @@ export class ConfigFactory { name: item.id, ...item, }); + + item?.advanced?.forEach((subItem) => { + ConfigFactory.settingsMap[subItem.id] = { + ...subItem, + }; + }); }); config?.children?.forEach((child) => ConfigFactory.registerSettings(child)); } diff --git a/app/client/src/utils/AnalyticsUtil.tsx b/app/client/src/utils/AnalyticsUtil.tsx index 58f81df395..3fb960150f 100644 --- a/app/client/src/utils/AnalyticsUtil.tsx +++ b/app/client/src/utils/AnalyticsUtil.tsx @@ -155,6 +155,7 @@ export type EventName = | "COMMENTS_ONBOARDING_MODAL_TRIGGERED" | "REPLAY_UNDO" | "REPLAY_REDO" + | "REDIRECT_URL_COPIED" | "SNIPPET_CUSTOMIZE" | "SNIPPET_EXECUTE" | "SNIPPET_FILTER" diff --git a/app/client/start-https.sh b/app/client/start-https.sh index 767d6ee0a9..8574b03b40 100755 --- a/app/client/start-https.sh +++ b/app/client/start-https.sh @@ -32,7 +32,7 @@ if ! test -f "$KEY_FILE" || ! test -f "$CERT_FILE"; then exit fi -ENV_FILE=../../.env +ENV_FILE=../../stacks/configuration/docker.env if ! test -f "$ENV_FILE"; then echo " Please populate the .env at the root of the project and run again @@ -62,7 +62,7 @@ fi docker rm -f wildcard-nginx || true uname_out="$(uname -s)" -vars_to_substitute="$(printf '\$%s,' $(grep -o "^APPSMITH_[A-Z0-9_]\+" ../../.env | xargs))" +vars_to_substitute="$(printf '\$%s,' $(grep -o "^APPSMITH_[A-Z0-9_]\+" "$ENV_FILE" | xargs))" client_proxy_pass="${default_client_proxy}" network_mode="bridge" case "${uname_out}" in diff --git a/app/server/envs/dev.env.example b/app/server/envs/dev.env.example index 6021f36831..938cedbb92 100644 --- a/app/server/envs/dev.env.example +++ b/app/server/envs/dev.env.example @@ -20,8 +20,11 @@ APPSMITH_CLOUD_SERVICES_BASE_URL="https://release-cs.appsmith.com" #APPSMITH_OAUTH2_GITHUB_CLIENT_ID="" #APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET="" +#APPSMITH_FORM_LOGIN_DISABLED= +#APPSMITH_SIGNUP_DISABLED= + #APPSMITH_SENTRY_DSN= #APPSMITH_SENTRY_ENVIRONMENT= #APPSMITH_RECAPTCHA_SITE_KEY="" -#APPSMITH_RECAPTCHA_SECRET_KEY="" \ No newline at end of file +#APPSMITH_RECAPTCHA_SECRET_KEY="" diff --git a/app/server/envs/docker.env.example b/app/server/envs/docker.env.example index a0daf519f5..bf8089f4b5 100644 --- a/app/server/envs/docker.env.example +++ b/app/server/envs/docker.env.example @@ -4,6 +4,8 @@ # APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET="" # APPSMITH_OAUTH2_GITHUB_CLIENT_ID="" # APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET="" +# APPSMITH_FORM_LOGIN_DISABLED= +# APPSMITH_SIGNUP_DISABLED= # APPSMITH_MAIL_ENABLED=true # APPSMITH_MAIL_HOST=localhost diff --git a/deploy/docker/templates/docker.env.sh b/deploy/docker/templates/docker.env.sh index ccfe67efb9..6dd2612d9d 100644 --- a/deploy/docker/templates/docker.env.sh +++ b/deploy/docker/templates/docker.env.sh @@ -20,6 +20,10 @@ APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET= APPSMITH_OAUTH2_GITHUB_CLIENT_ID= APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET= +# Form Login/Signup +APPSMITH_FORM_LOGIN_DISABLED= +APPSMITH_SIGNUP_DISABLED= + # Segment APPSMITH_SEGMENT_KEY= diff --git a/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh b/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh index 013a8e05e1..a29268857a 100644 --- a/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh +++ b/deploy/docker/templates/nginx/nginx-app-http.conf.template.sh @@ -53,6 +53,8 @@ server { sub_filter __APPSMITH_MAIL_ENABLED__ '\${APPSMITH_MAIL_ENABLED}'; sub_filter __APPSMITH_DISABLE_TELEMETRY__ '\${APPSMITH_DISABLE_TELEMETRY}'; sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '\${APPSMITH_RECAPTCHA_SITE_KEY}'; + sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '\${APPSMITH_FORM_LOGIN_DISABLED}'; + sub_filter __APPSMITH_SIGNUP_DISABLED__ '\${APPSMITH_SIGNUP_DISABLED}'; } location /api { diff --git a/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh b/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh index 2ded828679..2bfddd5ea8 100644 --- a/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh +++ b/deploy/docker/templates/nginx/nginx-app-https.conf.template.sh @@ -73,6 +73,8 @@ server { sub_filter __APPSMITH_MAIL_ENABLED__ '\${APPSMITH_MAIL_ENABLED}'; sub_filter __APPSMITH_DISABLE_TELEMETRY__ '\${APPSMITH_DISABLE_TELEMETRY}'; sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '\${APPSMITH_RECAPTCHA_SITE_KEY}'; + sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '\${APPSMITH_FORM_LOGIN_DISABLED}'; + sub_filter __APPSMITH_SIGNUP_DISABLED__ '\${APPSMITH_SIGNUP_DISABLED}'; } location /api { diff --git a/deploy/helm/README.md b/deploy/helm/README.md index 4240ef8b25..afaa99c8a0 100644 --- a/deploy/helm/README.md +++ b/deploy/helm/README.md @@ -198,6 +198,8 @@ To change Appsmith configurations, you can use configuration UI in application o | `applicationConfig.APPSMITH_ENCRYPTION_PASSWORD` | `""` | | `applicationConfig.APPSMITH_ENCRYPTION_SALT` | `""` | | `applicationConfig.APPSMITH_CUSTOM_DOMAIN` | `""` | +| `applicationConfig.APPSMITH_FORM_LOGIN_DISABLED` | `""` | +| `applicationConfig.APPSMITH_SIGNUP_DISABLED` | `""` | For example, to change the encryption salt configuration, you can run the following command: ``` diff --git a/deploy/helm/values.yaml b/deploy/helm/values.yaml index 0ee66ac4fc..a205827a45 100644 --- a/deploy/helm/values.yaml +++ b/deploy/helm/values.yaml @@ -274,6 +274,8 @@ applicationConfig: APPSMITH_OAUTH2_GOOGLE_CLIENT_SECRET: "" APPSMITH_OAUTH2_GITHUB_CLIENT_ID: "" APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET: "" + APPSMITH_FORM_LOGIN_DISABLED: "" + APPSMITH_SIGNUP_DISABLED: "" APPSMITH_CLIENT_LOG_LEVEL: "" APPSMITH_GOOGLE_MAPS_API_KEY: "" APPSMITH_MAIL_ENABLED: "" diff --git a/deploy/heroku/default.conf.template b/deploy/heroku/default.conf.template index 31186289cd..d0a6c49890 100644 --- a/deploy/heroku/default.conf.template +++ b/deploy/heroku/default.conf.template @@ -35,6 +35,8 @@ server { sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '${APPSMITH_RECAPTCHA_SECRET_KEY}'; sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '${APPSMITH_RECAPTCHA_ENABLED}'; sub_filter __APPSMITH_DISABLE_INTERCOM__ '${APPSMITH_DISABLE_INTERCOM}'; + sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '${APPSMITH_FORM_LOGIN_DISABLED}'; + sub_filter __APPSMITH_SIGNUP_DISABLED__ '${APPSMITH_SIGNUP_DISABLED}'; } diff --git a/deploy/k8s/scripts/appsmith-configmap.yaml.sh b/deploy/k8s/scripts/appsmith-configmap.yaml.sh index 6a588ec3ef..55da9eb1b1 100644 --- a/deploy/k8s/scripts/appsmith-configmap.yaml.sh +++ b/deploy/k8s/scripts/appsmith-configmap.yaml.sh @@ -34,5 +34,7 @@ data: APPSMITH_RECAPTCHA_SECRET_KEY: "" APPSMITH_RECAPTCHA_ENABLED: "false" APPSMITH_DISABLE_INTERCOM: "false" + APPSMITH_FORM_LOGIN_DISABLED: "false" + APPSMITH_SIGNUP_DISABLED: "true" # APPSMITH_PLUGIN_MAX_RESPONSE_SIZE_MB=5 EOF diff --git a/deploy/k8s/scripts/nginx-configmap.yaml b/deploy/k8s/scripts/nginx-configmap.yaml index b671c7cbde..0f51b16e3f 100644 --- a/deploy/k8s/scripts/nginx-configmap.yaml +++ b/deploy/k8s/scripts/nginx-configmap.yaml @@ -45,6 +45,8 @@ data: sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '${APPSMITH_RECAPTCHA_SECRET_KEY}'; sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '${APPSMITH_RECAPTCHA_ENABLED}'; sub_filter __APPSMITH_DISABLE_INTERCOM__ '${APPSMITH_DISABLE_INTERCOM}'; + sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '${APPSMITH_FORM_LOGIN_DISABLED}'; + sub_filter __APPSMITH_SIGNUP_DISABLED__ '${APPSMITH_SIGNUP_DISABLED}'; } }" diff --git a/deploy/template/docker.env.sh b/deploy/template/docker.env.sh index 10296fa719..0d4e88bb80 100644 --- a/deploy/template/docker.env.sh +++ b/deploy/template/docker.env.sh @@ -35,6 +35,11 @@ APPSMITH_MAIL_ENABLED=false # APPSMITH_OAUTH2_GITHUB_CLIENT_SECRET= # ********************************* +# ******** Form Login/Signup ******** +# APPSMITH_FORM_LOGIN_DISABLED= +# APPSMITH_SIGNUP_DISABLED= +# *********************************** + # ******** Google Maps *********** # APPSMITH_GOOGLE_MAPS_API_KEY= # ******************************** diff --git a/deploy/template/nginx_app.conf.sh b/deploy/template/nginx_app.conf.sh index 50440ae702..320b46f6d3 100644 --- a/deploy/template/nginx_app.conf.sh +++ b/deploy/template/nginx_app.conf.sh @@ -57,6 +57,8 @@ $NGINX_SSL_CMNT server_name $custom_domain ; sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '\${APPSMITH_RECAPTCHA_SECRET_KEY}'; sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '\${APPSMITH_RECAPTCHA_ENABLED}'; sub_filter __APPSMITH_DISABLE_INTERCOM__ '\${APPSMITH_DISABLE_INTERCOM}'; + sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '\${APPSMITH_FORM_LOGIN_DISABLED}'; + sub_filter __APPSMITH_SIGNUP_DISABLED__ '\${APPSMITH_SIGNUP_DISABLED}'; } @@ -114,6 +116,8 @@ $NGINX_SSL_CMNT sub_filter __APPSMITH_RECAPTCHA_SITE_KEY__ '\${APPSMITH_R $NGINX_SSL_CMNT sub_filter __APPSMITH_RECAPTCHA_SECRET_KEY__ '\${APPSMITH_RECAPTCHA_SECRET_KEY}'; $NGINX_SSL_CMNT sub_filter __APPSMITH_RECAPTCHA_ENABLED__ '\${APPSMITH_RECAPTCHA_ENABLED}'; $NGINX_SSL_CMNT sub_filter __APPSMITH_DISABLE_INTERCOM__ '\${APPSMITH_DISABLE_INTERCOM}'; +$NGINX_SSL_CMNT sub_filter __APPSMITH_FORM_LOGIN_DISABLED__ '${APPSMITH_FORM_LOGIN_DISABLED}'; +$NGINX_SSL_CMNT sub_filter __APPSMITH_SIGNUP_DISABLED__ '${APPSMITH_SIGNUP_DISABLED}'; $NGINX_SSL_CMNT } $NGINX_SSL_CMNT $NGINX_SSL_CMNT location /api {