feat: Refactor invite modal for handling RBAC updates (#16405)

* refactored code for invite modal changes for rbac

* code splitted some more files for refactoring invite modal component

* removed unused imports

* created new variable for handlers

* updated an import

* reverted a change

* refactored a section of code

* fixed a cypress test

* fixed a cypress test

* updated imports

* exported some entities
This commit is contained in:
Ankita Kinger 2022-09-02 22:45:08 +05:30 committed by GitHub
parent 8c4451a2fe
commit e28e89807c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
89 changed files with 1421 additions and 755 deletions

View File

@ -45,12 +45,13 @@ describe("Create new workspace and invite user & validate all roles", () => {
.first()
.click();
// click on selet a role
cy.wait(2000)
cy.xpath(HomePage.selectRole).click()
cy.get('.t--dropdown-option').should('have.length', 1).and('contain.text', `App Viewer - ${workspaceId}`)
cy.get(HomePage.closeBtn).click()
cy.wait(2000);
cy.xpath(HomePage.selectRole).click();
cy.get(".t--dropdown-option")
.should("have.length", 2)
.and("contain.text", `App Viewer - ${workspaceId}`);
cy.get(".t--dropdown-option").should("contain.text", `Select a role`);
cy.get(HomePage.closeBtn).click();
homePage.LaunchAppFromAppHover();
homePage.LogOutviaAPI();
@ -82,13 +83,19 @@ describe("Create new workspace and invite user & validate all roles", () => {
.first()
.click({ force: true });
// cy.xpath(homePage._editPageLanding).should("exist");
cy.wait(4000)
cy.xpath("//span[text()='SHARE']")
.click();
cy.wait(2000)
cy.xpath(HomePage.selectRole).click()
cy.get('.t--dropdown-option').should('have.length', 2).and('contain.text', `App Viewer - ${workspaceId}`, `Developer - ${workspaceId}`)
cy.get(HomePage.closeBtn).click()
cy.wait(4000);
cy.xpath("//span[text()='SHARE']").click();
cy.wait(2000);
cy.xpath(HomePage.selectRole).click();
cy.get(".t--dropdown-option")
.should("have.length", 3)
.and(
"contain.text",
`App Viewer - ${workspaceId}`,
`Developer - ${workspaceId}`,
);
cy.get(".t--dropdown-option").should("contain.text", `Select a role`);
cy.get(HomePage.closeBtn).click();
homePage.LogOutviaAPI();
});
@ -119,11 +126,21 @@ describe("Create new workspace and invite user & validate all roles", () => {
Cypress.env("TESTUSERNAME2"),
"App Viewer",
);
cy.wait(2000)
cy.xpath(HomePage.selectRole).click()
cy.get('.t--dropdown-option').should('have.length', 3).should("contain.text", `App Viewer - ${workspaceId}`, `Developer - ${workspaceId}`)
cy.get('.t--dropdown-option').should("contain.text", `Administrator - ${workspaceId}`)
cy.get(HomePage.closeBtn).click()
cy.wait(2000);
cy.xpath(HomePage.selectRole).click();
cy.get(".t--dropdown-option")
.should("have.length", 4)
.should(
"contain.text",
`App Viewer - ${workspaceId}`,
`Developer - ${workspaceId}`,
);
cy.get(".t--dropdown-option").should(
"contain.text",
`Administrator - ${workspaceId}`,
);
cy.get(".t--dropdown-option").should("contain.text", `Select a role`);
cy.get(HomePage.closeBtn).click();
homePage.LogOutviaAPI();
});
@ -139,4 +156,4 @@ describe("Create new workspace and invite user & validate all roles", () => {
});
homePage.NavigateToHome();
});
});
});

View File

@ -6,39 +6,44 @@ let dataSources = ObjectsRegistry.DataSources;
let queryName;
let datasourceName;
let pluginName = "Google Sheets";
let placeholderText = "{\n \"name\": {{nameInput.text}},\n \"dob\": {{dobPicker.formattedDate}},\n \"gender\": {{genderSelect.selectedOptionValue}} \n}"
let placeholderText =
'{\n "name": {{nameInput.text}},\n "dob": {{dobPicker.formattedDate}},\n "gender": {{genderSelect.selectedOptionValue}} \n}';
describe("Google Sheets datasource row objects placeholder", function() {
it("Bug: 16391 - Google Sheets DS, placeholder objects keys should have quotes", function() {
// create new Google Sheets datasource
dataSources.NavigateToDSCreateNew();
dataSources.CreatePlugIn(pluginName);
// navigate to create query tab and create a new query
cy.get("@createDatasource").then((httpResponse) => {
datasourceName = httpResponse.response.body.data.name;
// clicking on new query to write a query
cy.NavigateToQueryEditor();
cy.get(explorer.createNew).click();
cy.get("div:contains('" + datasourceName + " Query')").last().click();
// fill the create new api google sheets form
// and check for rowobject placeholder text
cy.get(datasource.gSheetsOperationDropdown).click();
cy.get(datasource.gSheetsInsertOneOption).click();
cy.get(datasource.gSheetsEntityDropdown).click();
cy.get(datasource.gSheetsSheetRowsOption).click();
cy.get(datasource.gSheetsCodeMirrorPlaceholder).should('have.text', placeholderText);
it("Bug: 16391 - Google Sheets DS, placeholder objects keys should have quotes", function() {
// create new Google Sheets datasource
dataSources.NavigateToDSCreateNew();
dataSources.CreatePlugIn(pluginName);
// delete query and datasource after test is done
cy.get("@createNewApi").then((httpResponse) => {
queryName = httpResponse.response.body.data.name;
cy.deleteQueryUsingContext();
cy.deleteDatasource(datasourceName);
})
// navigate to create query tab and create a new query
cy.get("@createDatasource").then((httpResponse) => {
datasourceName = httpResponse.response.body.data.name;
// clicking on new query to write a query
cy.NavigateToQueryEditor();
cy.get(explorer.createNew).click();
cy.get("div:contains('" + datasourceName + " Query')")
.last()
.click();
// fill the create new api google sheets form
// and check for rowobject placeholder text
cy.get(datasource.gSheetsOperationDropdown).click();
cy.get(datasource.gSheetsInsertOneOption).click();
cy.get(datasource.gSheetsEntityDropdown).click();
cy.get(datasource.gSheetsSheetRowsOption).click();
cy.get(datasource.gSheetsCodeMirrorPlaceholder).should(
"have.text",
placeholderText,
);
// delete query and datasource after test is done
cy.get("@createNewApi").then((httpResponse) => {
queryName = httpResponse.response.body.data.name;
cy.deleteQueryUsingContext();
cy.deleteDatasource(datasourceName);
});
});
}
);
});
});

View File

@ -24,11 +24,15 @@ export class HomePage {
".t--workspace-section:contains(" +
workspaceName +
") button:contains('Share')";
private _email = "//input[@type='email']";
private _email =
"//input[@type='text' and contains(@class,'bp3-input-ghost')]";
_visibleTextSpan = (spanText: string) => "//span[text()='" + spanText + "']";
private _userRole = (role: string, workspaceName: string) =>
"//div[contains(@class, 'label-container')]//span[1][text()='" +
role + ' - ' + workspaceName + "']";
role +
" - " +
workspaceName +
"']";
private _manageUsers = ".manageUsers";
private _appHome = "//a[@href='/applications']";
@ -50,8 +54,8 @@ export class HomePage {
"//td[text()='" +
email +
"']/following-sibling::td//span[contains(@class, 't--deleteUser')]";
private _userRoleDropDown = (role: string, WorkspaceName:string)=> "//span[text()='" +
role + " - "+ WorkspaceName + "']";
private _userRoleDropDown = (role: string, WorkspaceName: string) =>
"//span[text()='" + role + " - " + WorkspaceName + "']";
//private _userRoleDropDown = (email: string) => "//td[text()='" + email + "']/following-sibling::td"
private _leaveWorkspaceConfirmModal = ".t--member-delete-confirmation-modal";
private _workspaceImportAppModal = ".t--import-application-modal";
@ -160,8 +164,9 @@ export class HomePage {
cy.get(this._homeIcon).click({ force: true });
this.agHelper.Sleep(2000);
//cy.wait("@applications"); this randomly fails & introduces flakyness hence commenting!
this.agHelper.AssertElementVisible(this._homePageAppCreateBtn).then($ele=>
expect($ele).be.enabled);
this.agHelper
.AssertElementVisible(this._homePageAppCreateBtn)
.then(($ele) => expect($ele).be.enabled);
}
public CreateNewApplication() {
@ -181,7 +186,7 @@ export class HomePage {
this.agHelper.ValidateNetworkStatus("@createNewApplication", 201);
cy.get(this.locator._loading).should("not.exist");
this.agHelper.Sleep(2000);
if(appname) this.RenameApplication(appname);
if (appname) this.RenameApplication(appname);
cy.get(this._buildFromScratchActionCard).click();
//this.agHelper.ValidateNetworkStatus("@updateApplication", 200);
}
@ -310,7 +315,7 @@ export class HomePage {
cy.log(workspaceName, email, currentRole);
cy.xpath(this._userRoleDropDown(currentRole, workspaceName))
.first()
.click({force:true})
.click({ force: true });
//cy.xpath(this._userRoleDropDown(email)).first().click({force: true});
cy.xpath(this._visibleTextSpan(`${newRole} - ${workspaceName}`))
@ -353,7 +358,6 @@ export class HomePage {
cy.contains(successMessage);
}
public DeleteWorkspace(workspaceNameToDelete: string) {
cy.get(this._homeIcon).click();
this.agHelper.GetNClick(

View File

@ -1 +1,43 @@
export * from "constants/forms";
export const API_EDITOR_FORM_NAME = "ApiEditorForm";
export const CREATE_APPLICATION_FORM_NAME = "CreateApplicationForm";
export const INVITE_USERS_TO_WORKSPACE_FORM = "InviteUsersToWorkspaceForm";
export const LOGIN_FORM_NAME = "LoginForm";
export const LOGIN_FORM_EMAIL_FIELD_NAME = "username";
export const LOGIN_FORM_PASSWORD_FIELD_NAME = "password";
export const SIGNUP_FORM_NAME = "SignupForm";
export const SIGNUP_FORM_EMAIL_FIELD_NAME = "email";
export const FORGOT_PASSWORD_FORM_NAME = "ForgotPasswordForm";
export const RESET_PASSWORD_FORM_NAME = "ResetPasswordForm";
export const CREATE_PASSWORD_FORM_NAME = "CreatePasswordForm";
export const CREATE_WORKSPACE_FORM_NAME = "New Workspace";
export const CURL_IMPORT_FORM = "CurlImportForm";
export const QUERY_EDITOR_FORM_NAME = "QueryEditorForm";
export const API_HOME_SCREEN_FORM = "APIHomeScreenForm";
export const SAAS_EDITOR_FORM = "SaaSEditorForm";
export const DATASOURCE_DB_FORM = "DatasourceDBForm";
export const DATASOURCE_REST_API_FORM = "DatasourceRestAPIForm";
export const DATASOURCE_SAAS_FORM = "DatasourceSaaSForm";
export const WELCOME_FORM_NAME = "WelcomeSetupForm";
export const WELCOME_FORM_NAME_FIELD_NAME = "name";
export const WELCOME_FORM_EMAIL_FIELD_NAME = "email";
export const WELCOME_FORM_PASSWORD_FIELD_NAME = "password";
export const WELCOME_FORM_VERIFY_PASSWORD_FIELD_NAME = "verify_password";
export const WELCOME_FORM_ROLE_FIELD_NAME = "role";
export const WELCOME_FORM_ROLE_NAME_FIELD_NAME = "role_name";
export const WELCOME_FORM_USECASE_FIELD_NAME = "useCase";
export const WELCOME_FORM_CUSTOM_USECASE_FIELD_NAME = "custom_useCase";
export const SETTINGS_FORM_NAME = "SettingsForm";
export const WELCOME_NON_SUPER_FORM_NAME = "WelcomeNonSuperSetupForm";
export const SAVE_THEME_FORM_NAME = "SaveThemeForm";
export const REDIRECT_URL_FORM = "RedirectURLForm";
export const ENTITYID_URL_FORM = "EntityIdURLForm";
export const inviteModalLinks: any[] = [];

View File

@ -139,6 +139,8 @@ export const INVITE_USERS_ROLE_SELECT_PLACEHOLDER = () => `Select role`;
export const INVITE_USERS_ROLE_SELECT_LABEL = () => `Role`;
export const INVITE_USERS_EMAIL_LIST_LABEL = () => `User emails`;
export const INVITE_USERS_ADD_EMAIL_LIST_FIELD = () => `Add more`;
export const INVITE_USERS_MESSAGE = () => `Invite users`;
export const INVITE_USERS_PLACEHOLDER = () => `Enter email address`;
export const INVITE_USERS_SUBMIT_BUTTON_TEXT = () => `Invite users`;
export const INVITE_USERS_SUBMIT_SUCCESS = () =>
`The users have been invited successfully`;

View File

@ -51,7 +51,7 @@ export interface Setting {
isVisible?: (values: Record<string, any>) => boolean;
isHidden?: boolean;
isDisabled?: (values: Record<string, any>) => boolean;
calloutType?: "Info" | "Warning";
calloutType?: "Info" | "Warning" | "Notify";
advanced?: Setting[];
isRequired?: boolean;
formName?: string;

View File

@ -12,7 +12,7 @@ import {
LOGIN_FORM_NAME,
LOGIN_FORM_EMAIL_FIELD_NAME,
LOGIN_FORM_PASSWORD_FIELD_NAME,
} from "constants/forms";
} from "@appsmith/constants/forms";
import { FORGOT_PASSWORD_URL, SETUP, SIGN_UP_URL } from "constants/routes";
import {
LOGIN_PAGE_TITLE,

View File

@ -1,7 +1,7 @@
import React, { useEffect } from "react";
import { reduxForm, InjectedFormProps, formValueSelector } from "redux-form";
import { AUTH_LOGIN_URL } from "constants/routes";
import { SIGNUP_FORM_NAME } from "constants/forms";
import { SIGNUP_FORM_NAME } from "@appsmith/constants/forms";
import {
RouteComponentProps,
useHistory,
@ -48,7 +48,7 @@ import PerformanceTracker, {
PerformanceTransactionName,
} from "utils/PerformanceTracker";
import { SIGNUP_FORM_EMAIL_FIELD_NAME } from "constants/forms";
import { SIGNUP_FORM_EMAIL_FIELD_NAME } from "@appsmith/constants/forms";
import { getAppsmithConfigs } from "@appsmith/configs";
import { useScript, ScriptStatus, AddScriptTo } from "utils/hooks/useScript";

View File

@ -0,0 +1,985 @@
import React, {
Fragment,
useContext,
useEffect,
useState,
useMemo,
useRef,
} from "react";
import styled, {
createGlobalStyle,
css,
ThemeContext,
} from "styled-components";
import TagListField from "components/editorComponents/form/fields/TagListField";
import { reduxForm, SubmissionError } from "redux-form";
import SelectField from "components/editorComponents/form/fields/SelectField";
import { connect, useSelector } from "react-redux";
import { AppState } from "@appsmith/reducers";
import {
getRolesForField,
getAllUsers,
getCurrentAppWorkspace,
} from "@appsmith/selectors/workspaceSelectors";
import Spinner from "components/editorComponents/Spinner";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import {
InviteUsersToWorkspaceFormValues,
inviteUsersToWorkspace,
} from "@appsmith/pages/workspace/helpers";
import { INVITE_USERS_TO_WORKSPACE_FORM } from "@appsmith/constants/forms";
import {
createMessage,
INVITE_USERS_SUBMIT_SUCCESS,
INVITE_USER_SUBMIT_SUCCESS,
INVITE_USERS_VALIDATION_EMAILS_EMPTY,
INVITE_USERS_VALIDATION_EMAIL_LIST,
INVITE_USERS_VALIDATION_ROLE_EMPTY,
} from "@appsmith/constants/messages";
import { isEmail } from "utils/formhelpers";
import {
isPermitted,
PERMISSION_TYPE,
} from "pages/Applications/permissionHelpers";
import { getAppsmithConfigs } from "@appsmith/configs";
import { ReactComponent as NoEmailConfigImage } from "assets/images/email-not-configured.svg";
import AnalyticsUtil from "utils/AnalyticsUtil";
import {
Button,
Size,
Text,
TextType,
Icon,
IconSize,
SegmentHeader,
TextProps,
TooltipComponent,
DropdownOption,
} from "design-system";
import { Classes, Variant } from "components/ads/common";
import Callout from "components/ads/Callout";
import { getInitialsAndColorCode } from "utils/AppsmithUtils";
import ProfileImage from "pages/common/ProfileImage";
import ManageUsers from "pages/workspace/ManageUsers";
import { ScrollIndicator } from "design-system";
import UserApi from "@appsmith/api/UserApi";
import { Colors } from "constants/Colors";
import { fetchWorkspace } from "actions/workspaceActions";
import { SubTextPosition } from "components/constants";
import { Link } from "react-router-dom";
import { Tooltip } from "@blueprintjs/core";
import { isEllipsisActive } from "utils/helpers";
export const CommonTitleTextStyle = css`
color: ${Colors.CHARCOAL};
font-weight: normal;
`;
export const WorkspaceInviteWrapper = styled.div`
> div {
margin-top: 0;
}
`;
export const WorkspaceInviteTitle = styled.div`
padding: 0 0 10px 0;
& > span[type="h5"] {
${CommonTitleTextStyle}
}
`;
export const StyledForm = styled.form`
width: 100%;
background: ${(props) => props.theme.colors.modal.bg};
&&& {
.wrapper > div:nth-child(1) {
width: 60%;
}
.wrapper > div:nth-child(2) {
width: 40%;
}
.bp3-input {
box-shadow: none;
}
.bp3-button {
padding-top: 5px;
}
}
`;
export const ErrorBox = styled.div<{ message?: boolean }>`
${(props) =>
props.message ? `margin: ${props.theme.spaces[9]}px 0px;` : null};
`;
export const StyledInviteFieldGroup = styled.div`
display: flex;
align-items: baseline;
justify-content: space-between;
.wrapper {
display: flex;
width: 85%;
flex-direction: row;
align-items: baseline;
justify-content: space-between;
margin-right: ${(props) => props.theme.spaces[3]}px;
border-right: 0px;
}
`;
export const InviteModalStyles = createGlobalStyle`
.label-container > * {
word-break: break-word;
}
`;
export const UserList = styled.div`
margin-top: 24px;
max-height: 260px;
overflow-y: auto;
&&::-webkit-scrollbar-thumb {
background-color: ${(props) => props.theme.colors.modal.scrollbar};
}
`;
export const User = styled.div`
display: flex;
align-items: center;
min-height: 54px;
padding: 5px 0 5px 15px;
justify-content: space-between;
color: ${(props) => props.theme.colors.modal.user.textColor};
`;
export const UserInfo = styled.div`
display: inline-flex;
align-items: center;
div:first-child {
cursor: default;
}
`;
export const UserRole = styled.div`
flex-basis: 40%;
flex-shrink: 0;
.${Classes.TEXT} {
color: ${Colors.COD_GRAY};
display: inline-block;
width: 100%;
word-break: break-word;
}
`;
export const UserName = styled.div`
display: flex;
flex-direction: column;
margin: 0 10px;
span {
word-break: break-word;
&:nth-child(1) {
margin-bottom: 1px;
}
&[type="h5"] {
color: ${Colors.COD_GRAY};
}
&[type="p2"] {
color: ${Colors.GRAY};
}
}
`;
export const RoleDivider = styled.div`
border-top: 1px solid ${(props) => props.theme.colors.menuBorder};
`;
export const Loading = styled(Spinner)`
padding-top: 10px;
margin: auto;
width: 100%;
`;
export const MailConfigContainer = styled.div`
display: flex;
flex-direction: column;
padding: 24px 4px;
padding-bottom: 0;
align-items: center;
&& > span {
color: ${(props) => props.theme.colors.modal.email.message};
font-weight: 500;
font-size: 14px;
}
&& > a {
color: ${(props) => props.theme.colors.modal.email.desc};
font-size: 12px;
text-decoration: underline;
}
`;
export const LabelText = styled(Text)`
font-size: 14px;
color: ${Colors.GREY_8};
margin-bottom: 8px;
line-height: 1.57;
letter-spacing: -0.24px;
`;
/*const LinksWrapper = styled.div`
&:before {
border-top: 1px solid var(--appsmith-color-black-200);
content: "";
position: absolute;
left: 12px;
right: 12px;
}
`;*/
export const LeftIconWrapper = styled.span`
font-size: 20px;
line-height: 19px;
margin-right: 10px;
height: 100%;
position: relative;
top: 1px;
`;
export const SelectedIcon = styled(Icon)<{ name: string }>`
margin-right: 6px;
& > div:first-child {
height: 18px;
width: 18px;
svg {
height: 18px;
width: 18px;
rect {
fill: ${(props) => props.theme.colors.dropdownIconBg};
rx: 0;
}
path {
fill: ${(props) => props.theme.colors.propertyPane.label};
}
}
}
svg {
${(props) =>
props.name === "right-arrow" ? `transform: rotate(-45deg);` : ``}
path {
fill: ${(props) =>
props.fillColor
? props.fillColor
: props.theme.colors.dropdown.selected.icon};
}
}
`;
export const StyledSubText = styled(Text)<{
showDropIcon?: boolean;
subTextPosition?: SubTextPosition;
}>`
${(props) =>
props.subTextPosition === SubTextPosition.BOTTOM
? "margin-top: 3px"
: "margin-left: auto"};
&&& {
color: ${(props) => props.theme.colors.dropdown.menu.subText};
}
&.sub-text {
color: ${(props) => props.theme.colors.dropdown.selected.subtext};
text-align: end;
margin-right: ${(props) => `${props.theme.spaces[4]}px`};
}
`;
export const OptionWrapper = styled.div<{
disabled?: boolean;
selected: boolean;
subTextPosition?: SubTextPosition;
selectedHighlightBg?: string;
}>`
padding: ${(props) => props.theme.spaces[3] + 1}px
${(props) => props.theme.spaces[5]}px;
${(props) => (!props.disabled ? "cursor: pointer" : "")};
display: flex;
width: 100%;
min-height: 36px;
flex-direction: ${(props) =>
props.subTextPosition === SubTextPosition.BOTTOM ? "column" : "row"};
align-items: ${(props) =>
props.subTextPosition === SubTextPosition.BOTTOM ? "flex-start" : "center"};
background-color: ${(props) =>
props.selected
? props.selectedHighlightBg || `var(--appsmith-color-black-200)`
: `initial`};
&&& svg {
rect {
fill: ${(props) => props.theme.colors.dropdownIconBg};
}
}
.bp3-popover-wrapper {
width: 100%;
}
.${Classes.TEXT} {
color: ${(props) =>
props.disabled
? Colors.GRAY2
: props.selected
? props.theme.colors.dropdown.menu.hoverText
: props.theme.colors.dropdown.menu.text};
}
.${Classes.ICON} {
margin-right: ${(props) => props.theme.spaces[5]}px;
svg {
path {
${(props) =>
props.selected
? `fill: ${props.theme.colors.dropdown.selected.icon}`
: `fill: ${props.theme.colors.dropdown.icon}`};
}
}
}
&:hover {
background-color: ${(props) => props.selectedHighlightBg || `initial`};
&&& svg {
rect {
fill: ${(props) => props.theme.colors.textOnDarkBG};
}
}
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.dropdown.menu.hoverText};
}
${StyledSubText} {
color: ${(props) => props.theme.colors.dropdown.menu.subText};
}
.${Classes.ICON} {
svg {
path {
fill: ${(props) => props.theme.colors.dropdown.hovered.icon};
}
}
}
}
`;
export const StyledText = styled(Text)`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
export const LabelWrapper = styled.div<{ label?: string }>`
display: flex;
flex-direction: column;
align-items: flex-start;
span:last-child {
margin-top: ${(props) => props.theme.spaces[2] - 1}px;
}
&:hover {
.${Classes.TEXT} {
color: ${(props) => props.theme.colors.dropdown.selected.text};
}
}
`;
export function TooltipWrappedText(
props: TextProps & {
label: string;
},
) {
const { label, ...textProps } = props;
const targetRef = useRef<HTMLDivElement | null>(null);
return (
<Tooltip
boundary="window"
content={label}
disabled={!isEllipsisActive(targetRef.current)}
position="top"
>
<StyledText ref={targetRef} {...textProps}>
{label}
</StyledText>
</Tooltip>
);
}
const validateFormValues = (values: {
users: string;
role?: string;
roles?: Partial<DropdownOption>[];
}) => {
if (values.users && values.users.length > 0) {
const _users = values.users.split(",").filter(Boolean);
_users.forEach((user) => {
if (!isEmail(user)) {
throw new SubmissionError({
_error: createMessage(INVITE_USERS_VALIDATION_EMAIL_LIST),
});
}
});
} else {
throw new SubmissionError({
_error: createMessage(INVITE_USERS_VALIDATION_EMAILS_EMPTY),
});
}
if (
typeof values.roles === "undefined" &&
(typeof values.role === "undefined" || values.role?.trim().length === 0)
) {
throw new SubmissionError({
_error: createMessage(INVITE_USERS_VALIDATION_ROLE_EMPTY),
});
}
if (
typeof values.role === "undefined" &&
(typeof values.roles === "undefined" || values.roles.length === 0)
) {
throw new SubmissionError({
_error: createMessage(INVITE_USERS_VALIDATION_ROLE_EMPTY),
});
}
};
const validate = (values: any) => {
const errors: any = {};
if (!(values.users && values.users.length > 0)) {
errors["users"] = createMessage(INVITE_USERS_VALIDATION_EMAILS_EMPTY);
}
if (
typeof values.roles === "undefined" &&
(typeof values.role === "undefined" || values.role?.trim().length === 0)
) {
errors["role"] = createMessage(INVITE_USERS_VALIDATION_ROLE_EMPTY);
}
if (
typeof values.role === "undefined" &&
(typeof values.roles === "undefined" || values.roles.length === 0)
) {
errors["roles"] = createMessage(INVITE_USERS_VALIDATION_ROLE_EMPTY);
}
if (values.users && values.users.length > 0) {
const _users = values.users.split(",").filter(Boolean);
_users.forEach((user: string) => {
if (!isEmail(user)) {
errors["users"] = createMessage(INVITE_USERS_VALIDATION_EMAIL_LIST);
}
});
}
return errors;
};
export const { mailEnabled } = getAppsmithConfigs();
export const InviteButtonWidth = "88px";
function WorkspaceInviteUsersForm(props: any) {
const [emailError, setEmailError] = useState("");
const [selectedOption, setSelectedOption] = useState<any>({});
const userRef = React.createRef<HTMLDivElement>();
const selectedId = props?.selected?.id;
const multiSelectDropdownOptions: Partial<DropdownOption>[] =
props.options && props.options.length > 0 && props.isMultiSelectDropdown
? props.options
: [];
const selected = useMemo(
() =>
selectedId &&
props.selected && {
label: props.selected.rolename,
value: props.selected.rolename,
id: props.selected.id,
},
[selectedId],
);
const {
allUsers,
anyTouched,
disableEmailSetup = false,
disableManageUsers = false,
disableUserList = false,
error,
fetchAllRoles,
fetchCurrentWorkspace,
fetchUser,
handleSubmit,
isAclFlow = false,
isApplicationInvite,
isLoading,
isMultiSelectDropdown = false,
links = [],
message = "",
placeholder = "",
submitFailed,
submitSucceeded,
submitting,
valid,
} = props;
const [selectedItems, setSelectedItems] = useState<any[]>([]);
// set state for checking number of users invited
const [numberOfUsersInvited, updateNumberOfUsersInvited] = useState(0);
const currentWorkspace = useSelector(getCurrentAppWorkspace);
const userWorkspacePermissions = currentWorkspace?.userPermissions ?? [];
const canManage = isPermitted(
userWorkspacePermissions,
PERMISSION_TYPE.MANAGE_WORKSPACE,
);
useEffect(() => {
if (!isAclFlow) {
fetchUser(props.workspaceId);
fetchAllRoles(props.workspaceId);
fetchCurrentWorkspace(props.workspaceId);
}
}, [props.workspaceId, fetchUser, fetchAllRoles, fetchCurrentWorkspace]);
useEffect(() => {
if (selected) {
setSelectedItems([selected]);
props.initialize({
roles: [selected],
});
}
}, []);
const styledRoles = props.roles.map((role: any) => {
return {
id: role.id,
value: role.name,
label: role.description,
};
});
styledRoles.push(...links);
const theme = useContext(ThemeContext);
const allUsersProfiles = React.useMemo(
() =>
allUsers.map(
(user: {
userId: string;
username: string;
permissionGroupId: string;
permissionGroupName: string;
name: string;
}) => {
const details = getInitialsAndColorCode(
user.name || user.username,
theme.colors.appCardColors,
);
return {
...user,
initials: details[0],
};
},
),
[allUsers, theme],
);
const onSelect = (_value?: string, options?: any) => {
setSelectedItems(options);
};
const onRemoveOptions = (updatedItems: any) => {
setSelectedItems(updatedItems);
};
const getLabel = (selectedOption: Partial<DropdownOption>[]) => {
return (
<span data-testid="t--dropdown-label" style={{ width: "100%" }}>
<Text type={TextType.P1}>{`${
selected
? selectedOption[0].label
: `${selectedOption?.length} Selected`
}`}</Text>
</span>
);
};
const errorHandler = (error: string, values: string[]) => {
if (values && values.length > 0) {
let error = "";
values.forEach((user: any) => {
if (!isEmail(user)) {
error = createMessage(INVITE_USERS_VALIDATION_EMAIL_LIST);
}
});
setEmailError(error);
} else {
props.customError?.("");
}
};
const renderOption = ({
index,
option,
optionClickHandler,
}: {
index?: number;
option: DropdownOption | DropdownOption[];
optionClickHandler?: (dropdownOption: DropdownOption) => void;
}) => {
let isSelected = false;
if (props.isMultiSelect && Array.isArray(selected) && selected.length) {
isSelected = !!selected.find((selectedOption: any) =>
!Array.isArray(option) ? selectedOption.value === option.value : false,
);
} else {
isSelected =
!Array.isArray(option) && selected
? selected.value === option.value
: false;
}
return !Array.isArray(option) && !option.isSectionHeader ? (
!option.link ? (
<TooltipComponent
content={
!!option.disabledTooltipText
? option.disabledTooltipText
: "Action not supported"
}
disabled={!option.disabled}
key={`tootltip-${index}`}
styles={{
width: "100%",
}}
>
<OptionWrapper
aria-selected={isSelected}
className={`t--dropdown-option ${isSelected ? "selected" : ""}`}
data-cy={`t--dropdown-option-${option?.label}`}
disabled={option.disabled}
key={index}
onClick={
// users should be able to unselect a selected option by clicking the option again.
isSelected && props.allowDeselection
? () => props.removeSelectedOptionClickHandler(option)
: () => optionClickHandler?.(option)
}
role="option"
selected={
props.isMultiSelect ? props.highlightIndex === index : isSelected
}
selectedHighlightBg={props.selectedHighlightBg}
subTextPosition={option.subTextPosition ?? SubTextPosition.LEFT}
>
{option.leftElement && (
<LeftIconWrapper>{option.leftElement}</LeftIconWrapper>
)}
{option.icon ? (
<SelectedIcon
fillColor={option?.iconColor}
hoverFillColor={option?.iconColor}
name={option.icon}
size={option.iconSize || IconSize.XL}
/>
) : null}
{props.showLabelOnly ? (
props.truncateOption ? (
<>
<TooltipWrappedText
label={option.label || ""}
type={TextType.P1}
/>
{option.hasCustomBadge && props.customBadge}
</>
) : (
<>
<Text type={TextType.P1}>{option.label}</Text>
{option.hasCustomBadge && props.customBadge}
</>
)
) : option.label && option.value ? (
<LabelWrapper className="label-container">
<Text type={TextType.H5}>{option.value}</Text>
<Text type={TextType.P1}>{option.label}</Text>
</LabelWrapper>
) : props.truncateOption ? (
<TooltipWrappedText
label={option.value || ""}
type={TextType.P1}
/>
) : (
<Text type={TextType.P1}>{option.value}</Text>
)}
{option.subText ? (
<StyledSubText
subTextPosition={option.subTextPosition}
type={TextType.P3}
>
{option.subText}
</StyledSubText>
) : null}
</OptionWrapper>
</TooltipComponent>
) : (
<Link key={index} to={option.link || "/"}>
<OptionWrapper
className={`t--dropdown-link`}
data-cy={`t--dropdown-option-${option?.value}`}
disabled={option.disabled}
role="option"
selected={false}
selectedHighlightBg={props.selectedHighlightBg}
subTextPosition={option.subTextPosition ?? SubTextPosition.LEFT}
>
{option.leftElement && (
<LeftIconWrapper>{option.leftElement}</LeftIconWrapper>
)}
{option.icon ? (
<SelectedIcon
fillColor={option?.iconColor}
hoverFillColor={option?.iconColor}
name={option.icon}
size={option.iconSize || IconSize.XL}
/>
) : null}
<Text type={TextType.P1}>{option.value}</Text>
{option.subText ? (
<StyledSubText
subTextPosition={option.subTextPosition}
type={TextType.P3}
>
{option.subText}
</StyledSubText>
) : null}
</OptionWrapper>
</Link>
)
) : (
<SegmentHeader
key={index}
style={{ paddingRight: theme.spaces[5] }}
title={!Array.isArray(option) && option.label ? option.label : ""}
/>
);
};
return (
<WorkspaceInviteWrapper>
<InviteModalStyles />
{isApplicationInvite && (
<WorkspaceInviteTitle>
<Text type={TextType.H5}>
Invite users to {currentWorkspace?.name}{" "}
</Text>
</WorkspaceInviteTitle>
)}
<StyledForm
onSubmit={handleSubmit((values: any, dispatch: any) => {
validateFormValues(values);
AnalyticsUtil.logEvent("INVITE_USER", values);
const usersAsStringsArray = values.users.split(",");
// update state to show success message correctly
updateNumberOfUsersInvited(usersAsStringsArray.length);
const users = usersAsStringsArray
.filter((user: any) => isEmail(user))
.join(",");
return inviteUsersToWorkspace(
{
...values,
users,
permissionGroupId: selectedOption.id,
workspaceId: props.workspaceId,
},
dispatch,
);
})}
>
<LabelText type={TextType.P0}>{message}</LabelText>
<StyledInviteFieldGroup>
<div className="wrapper">
<TagListField
autofocus
customError={(err: string, values?: string[]) =>
errorHandler(err, values || [])
}
data-cy="t--invite-email-input"
intent="success"
label="Emails"
name="users"
placeholder={placeholder || "Enter email address"}
type="text"
/>
{isMultiSelectDropdown ? (
<SelectField
allowDeselection
disabled={!!selected}
isMultiSelect
labelRenderer={(selected: Partial<DropdownOption>[]) =>
getLabel(selected)
}
name="roles"
onSelect={onSelect}
options={multiSelectDropdownOptions}
outline={false}
placeholder="Select a role"
removeSelectedOption={onRemoveOptions}
selected={selectedItems}
showLabelOnly
size="small"
/>
) : (
<SelectField
data-cy="t--invite-role-input"
name="role"
onSelect={(value, option) => setSelectedOption(option)}
options={styledRoles}
outline={false}
placeholder="Select a role"
renderOption={renderOption}
size="small"
/>
)}
</div>
<Button
className="t--invite-user-btn"
disabled={!valid}
isLoading={submitting && !(submitFailed && !anyTouched)}
size={Size.large}
tag="button"
text="Invite"
variant={Variant.info}
width={InviteButtonWidth}
/>
</StyledInviteFieldGroup>
{isLoading ? (
<Loading size={30} />
) : (
<>
{!mailEnabled && !disableEmailSetup && (
<MailConfigContainer>
{allUsers.length === 0 && <NoEmailConfigImage />}
<span>You havent setup any email service yet</span>
<a
href="https://docs.appsmith.com/v/v1.2.1/setup/docker/email"
rel="noopener noreferrer"
target="_blank"
>
Please configure your email service to invite people
</a>
</MailConfigContainer>
)}
{!disableUserList && (
<UserList
ref={userRef}
style={{ justifyContent: "space-between" }}
>
{allUsersProfiles.map(
(user: {
username: string;
name: string;
permissionGroupId: string;
permissionGroupName: string;
initials: string;
}) => {
return (
<Fragment key={user.username}>
<User>
<UserInfo>
<ProfileImage
source={`/api/${UserApi.photoURL}/${user.username}`}
userName={user.name || user.username}
/>
<UserName>
<Text type={TextType.H5}>{user.name}</Text>
<Text type={TextType.P2}>{user.username}</Text>
</UserName>
</UserInfo>
<UserRole>
<Text type={TextType.P1}>
{user.permissionGroupName}
</Text>
</UserRole>
</User>
<RoleDivider />
</Fragment>
);
},
)}
<ScrollIndicator containerRef={userRef} mode="DARK" />
</UserList>
)}
</>
)}
<ErrorBox message={submitSucceeded || submitFailed}>
{submitSucceeded && (
<Callout
fill
text={
numberOfUsersInvited > 1
? createMessage(INVITE_USERS_SUBMIT_SUCCESS)
: createMessage(INVITE_USER_SUBMIT_SUCCESS)
}
variant={Variant.success}
/>
)}
{((submitFailed && error) || emailError) && (
<Callout fill text={error || emailError} variant={Variant.danger} />
)}
</ErrorBox>
{canManage && !disableManageUsers && (
<ManageUsers workspaceId={props.workspaceId} />
)}
</StyledForm>
</WorkspaceInviteWrapper>
);
}
export default connect(
(state: AppState, { formName }: { formName?: string }) => {
return {
roles: getRolesForField(state),
allUsers: getAllUsers(state),
isLoading: state.ui.workspaces.loadingStates.isFetchAllUsers,
form: formName || INVITE_USERS_TO_WORKSPACE_FORM,
};
},
(dispatch: any) => ({
fetchAllRoles: (workspaceId: string) =>
dispatch({
type: ReduxActionTypes.FETCH_ALL_ROLES_INIT,
payload: {
workspaceId,
},
}),
fetchCurrentWorkspace: (workspaceId: string) =>
dispatch(fetchWorkspace(workspaceId)),
fetchUser: (workspaceId: string) =>
dispatch({
type: ReduxActionTypes.FETCH_ALL_USERS_INIT,
payload: {
workspaceId,
},
}),
}),
)(
reduxForm<
InviteUsersToWorkspaceFormValues,
{
fetchAllRoles: (workspaceId: string) => void;
roles?: any;
applicationId?: string;
workspaceId?: string;
isApplicationInvite?: boolean;
links?: any[];
}
>({
validate,
})(WorkspaceInviteUsersForm),
);

View File

@ -12,7 +12,7 @@ import { WidgetConfigReducerState } from "reducers/entityReducers/widgetConfigRe
import { DatasourceDataState } from "reducers/entityReducers/datasourceReducer";
import { AppViewReduxState } from "reducers/uiReducers/appViewReducer";
import { DatasourcePaneReduxState } from "reducers/uiReducers/datasourcePaneReducer";
import { ApplicationsReduxState } from "reducers/uiReducers/applicationsReducer";
import { ApplicationsReduxState } from "@appsmith/reducers/uiReducers/applicationsReducer";
import { PageListReduxState } from "reducers/entityReducers/pageListReducer";
import { ApiPaneReduxState } from "reducers/uiReducers/apiPaneReducer";
import { QueryPaneReduxState } from "reducers/uiReducers/queryPaneReducer";

View File

@ -15,7 +15,7 @@ import { CreateApplicationFormValues } from "pages/Applications/helpers";
import { AppLayoutConfig } from "reducers/entityReducers/pageListReducer";
import { ConnectToGitResponse } from "actions/gitSyncActions";
const initialState: ApplicationsReduxState = {
export const initialState: ApplicationsReduxState = {
isFetchingApplications: false,
isSavingAppName: false,
isErrorSavingAppName: false,
@ -35,7 +35,7 @@ const initialState: ApplicationsReduxState = {
workspaceIdForImport: null,
};
const applicationsReducer = createReducer(initialState, {
export const handlers = {
[ReduxActionTypes.DELETE_APPLICATION_INIT]: (
state: ApplicationsReduxState,
) => {
@ -487,7 +487,9 @@ const applicationsReducer = createReducer(initialState, {
applicationList: [...state.applicationList, action.payload],
};
},
});
};
const applicationsReducer = createReducer(initialState, handlers);
export type creatingApplicationMap = Record<string, boolean>;

View File

@ -9,7 +9,7 @@ import {
} from "@appsmith/constants/ReduxActionConstants";
import { APPLICATIONS_URL } from "constants/routes";
import { User } from "constants/userConstants";
import { takeLatest, all, call, put, delay, select } from "redux-saga/effects";
import { call, put, delay, select } from "redux-saga/effects";
import history from "utils/history";
import { validateResponse } from "sagas/ErrorSagas";
import { getAppsmithConfigs } from "@appsmith/configs";
@ -103,7 +103,7 @@ export function* RestartServerPoll() {
yield call(RestryRestartServerPoll);
}
function* RestryRestartServerPoll() {
export function* RestryRestartServerPoll() {
let pollCount = 0;
const maxPollCount = RESTART_POLL_TIMEOUT / RESTART_POLL_INTERVAL;
while (pollCount < maxPollCount) {
@ -156,30 +156,3 @@ export function* SendTestEmail(action: ReduxAction<SendTestEmailPayload>) {
}
} catch (e) {}
}
export function* InitSuperUserSaga(action: ReduxAction<User>) {
const user = action.payload;
if (user.isSuperUser) {
yield all([
takeLatest(ReduxActionTypes.FETCH_ADMIN_SETTINGS, FetchAdminSettingsSaga),
takeLatest(
ReduxActionTypes.FETCH_ADMIN_SETTINGS_ERROR,
FetchAdminSettingsErrorSaga,
),
takeLatest(ReduxActionTypes.SAVE_ADMIN_SETTINGS, SaveAdminSettingsSaga),
takeLatest(ReduxActionTypes.RESTART_SERVER_POLL, RestartServerPoll),
takeLatest(
ReduxActionTypes.RETRY_RESTART_SERVER_POLL,
RestryRestartServerPoll,
),
takeLatest(ReduxActionTypes.SEND_TEST_EMAIL, SendTestEmail),
]);
}
}
export default function* SuperUserSagas() {
yield takeLatest(
ReduxActionTypes.FETCH_USER_DETAILS_SUCCESS,
InitSuperUserSaga,
);
}

View File

@ -11,7 +11,7 @@ import { watchDatasourcesSagas } from "sagas/DatasourcesSagas";
import initSagas from "sagas/InitSagas";
import apiPaneSagas from "sagas/ApiPaneSagas";
import jsPaneSagas from "sagas/JSPaneSagas";
import userSagas from "sagas/userSagas";
import userSagas from "@appsmith/sagas/userSagas";
import pluginSagas from "sagas/PluginSagas";
import workspaceSagas from "sagas/WorkspaceSagas";
import importedCollectionsSagas from "sagas/CollectionSagas";

View File

@ -1,4 +1,4 @@
import { call, takeLatest, put, all, select, take } from "redux-saga/effects";
import { call, put, select, take } from "redux-saga/effects";
import {
ReduxAction,
ReduxActionWithPromise,
@ -22,7 +22,7 @@ import {
validateResponse,
getResponseErrorMessage,
callAPI,
} from "./ErrorSagas";
} from "sagas/ErrorSagas";
import {
logoutUserSuccess,
logoutUserError,
@ -34,7 +34,7 @@ import {
fetchFeatureFlagsError,
} from "actions/userActions";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { INVITE_USERS_TO_WORKSPACE_FORM } from "constants/forms";
import { INVITE_USERS_TO_WORKSPACE_FORM } from "@appsmith/constants/forms";
import PerformanceTracker, {
PerformanceTransactionName,
} from "utils/PerformanceTracker";
@ -406,7 +406,9 @@ export function* waitForFetchUserSuccess() {
}
}
function* removePhoto(action: ReduxAction<{ callback: (id: string) => void }>) {
export function* removePhoto(
action: ReduxAction<{ callback: (id: string) => void }>,
) {
try {
const response: ApiResponse = yield call(UserApi.deletePhoto);
//@ts-expect-error: response is of type unknown
@ -417,7 +419,7 @@ function* removePhoto(action: ReduxAction<{ callback: (id: string) => void }>) {
}
}
function* updatePhoto(
export function* updatePhoto(
action: ReduxAction<{ file: File; callback: (id: string) => void }>,
) {
try {
@ -432,7 +434,7 @@ function* updatePhoto(
}
}
function* fetchFeatureFlags() {
export function* fetchFeatureFlags() {
try {
const response: ApiResponse = yield call(UserApi.fetchFeatureFlags);
const isValidResponse: boolean = yield validateResponse(response);
@ -446,7 +448,7 @@ function* fetchFeatureFlags() {
}
}
function* updateFirstTimeUserOnboardingSage() {
export function* updateFirstTimeUserOnboardingSage() {
const enable: string | null = yield getEnableFirstTimeUserOnboarding();
if (enable) {
@ -470,38 +472,6 @@ function* updateFirstTimeUserOnboardingSage() {
}
}
export default function* userSagas() {
yield all([
takeLatest(ReduxActionTypes.CREATE_USER_INIT, createUserSaga),
takeLatest(ReduxActionTypes.FETCH_USER_INIT, getCurrentUserSaga),
takeLatest(ReduxActionTypes.FORGOT_PASSWORD_INIT, forgotPasswordSaga),
takeLatest(ReduxActionTypes.RESET_USER_PASSWORD_INIT, resetPasswordSaga),
takeLatest(
ReduxActionTypes.RESET_PASSWORD_VERIFY_TOKEN_INIT,
verifyResetPasswordTokenSaga,
),
takeLatest(ReduxActionTypes.INVITE_USERS_TO_WORKSPACE_INIT, inviteUsers),
takeLatest(ReduxActionTypes.LOGOUT_USER_INIT, logoutSaga),
takeLatest(ReduxActionTypes.VERIFY_INVITE_INIT, verifyUserInviteSaga),
takeLatest(
ReduxActionTypes.INVITED_USER_SIGNUP_INIT,
invitedUserSignupSaga,
),
takeLatest(
ReduxActionTypes.UPDATE_USER_DETAILS_INIT,
updateUserDetailsSaga,
),
takeLatest(ReduxActionTypes.REMOVE_PROFILE_PHOTO, removePhoto),
takeLatest(ReduxActionTypes.UPLOAD_PROFILE_PHOTO, updatePhoto),
takeLatest(ReduxActionTypes.LEAVE_WORKSPACE_INIT, leaveWorkspaceSaga),
takeLatest(ReduxActionTypes.FETCH_FEATURE_FLAGS_INIT, fetchFeatureFlags),
takeLatest(
ReduxActionTypes.FETCH_USER_DETAILS_SUCCESS,
updateFirstTimeUserOnboardingSage,
),
]);
}
export function* leaveWorkspaceSaga(
action: ReduxAction<LeaveWorkspaceRequest>,
) {

View File

@ -1,7 +1,7 @@
import { render, screen } from "test/testUtils";
import React from "react";
import { CopyUrlReduxForm } from "./CopyUrlForm";
import { REDIRECT_URL_FORM } from "constants/forms";
import { REDIRECT_URL_FORM } from "@appsmith/constants/forms";
let container: any = null;

View File

@ -1,7 +1,7 @@
import { render } from "test/testUtils";
import React from "react";
import UneditableField from "./UneditableField";
import { REDIRECT_URL_FORM } from "constants/forms";
import { REDIRECT_URL_FORM } from "@appsmith/constants/forms";
import { reduxForm } from "redux-form";
let container: any = null;

View File

@ -3,13 +3,33 @@ import { isPermitted } from "pages/Applications/permissionHelpers";
import Dialog from "components/ads/DialogComponent";
import { useDispatch } from "react-redux";
import { setShowAppInviteUsersDialog } from "actions/applicationActions";
import { IconName } from "design-system";
import { TabComponent, TabProp } from "components/ads/Tabs";
import { Text, TextType, IconName } from "design-system";
import styled from "styled-components";
import { Colors } from "constants/Colors";
import { INVITE_USERS_TO_WORKSPACE_FORM } from "@appsmith/constants/forms";
const LabelText = styled(Text)`
font-size: 14px;
color: ${Colors.GREY_8};
margin-bottom: 8px;
line-height: 1.57;
letter-spacing: -0.24px;
`;
const TabWrapper = styled.div`
.react-tabs__tab-list {
margin: 16px 0;
border-bottom: 2px solid var(--appsmith-color-black-200);
}
`;
type FormDialogComponentProps = {
isOpen?: boolean;
canOutsideClickClose?: boolean;
workspaceId?: string;
title: string;
message?: string;
Form: any;
trigger: ReactNode;
onClose?: () => void;
@ -24,28 +44,67 @@ type FormDialogComponentProps = {
hoverColor?: string;
bgColor?: string;
};
selected?: any;
tabs?: any[];
options?: any[];
links?: any[];
placeholder?: string;
};
const getTabs = (
tabs: any[],
setIsOpen: (val: boolean) => void,
applicationId?: string,
workspaceId?: string,
) => {
return tabs && tabs.length > 0
? tabs.map((tab) => {
const TabForm = tab.component;
return {
key: tab.key,
title: tab.title,
panelComponent: (
<TabForm
{...tab.customProps}
applicationId={applicationId}
formName={`${INVITE_USERS_TO_WORKSPACE_FORM}_${tab.key}`}
onCancel={() => setIsOpen(false)}
options={tab.options}
placeholder={tab.placeholder || ""}
workspaceId={workspaceId}
/>
),
};
})
: [];
};
export function FormDialogComponent(props: FormDialogComponentProps) {
const [isOpen, setIsOpenState] = useState(!!props.isOpen);
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
const dispatch = useDispatch();
useEffect(() => {
setIsOpen(!!props.isOpen);
}, [props.isOpen]);
const setIsOpen = (isOpen: boolean) => {
setIsOpenState(isOpen);
dispatch(setShowAppInviteUsersDialog(isOpen));
};
useEffect(() => {
setIsOpen(!!props.isOpen);
}, [props.isOpen]);
const Form = props.Form;
const onCloseHandler = () => {
props?.onClose?.();
setIsOpen(false);
};
const updatedTabs: TabProp[] =
props.tabs && props.tabs.length > 0
? getTabs(props.tabs, setIsOpen, props.applicationId, props.workspaceId)
: [];
const Form = props.Form;
if (
props.permissions &&
props.permissionRequired &&
@ -65,12 +124,27 @@ export function FormDialogComponent(props: FormDialogComponentProps) {
title={props.title}
trigger={props.trigger}
>
<Form
{...props.customProps}
applicationId={props.applicationId}
onCancel={() => setIsOpen(false)}
workspaceId={props.workspaceId}
/>
{updatedTabs && updatedTabs.length > 0 ? (
<TabWrapper>
<LabelText type={TextType.P0}>{props.message}</LabelText>
<TabComponent
onSelect={setSelectedTabIndex}
selectedIndex={selectedTabIndex}
tabs={updatedTabs}
/>
</TabWrapper>
) : (
<Form
{...props.customProps}
applicationId={props.applicationId}
links={props.links}
message={props.message}
onCancel={() => setIsOpen(false)}
placeholder={props.placeholder}
selected={props.selected}
workspaceId={props.workspaceId}
/>
)}
</Dialog>
);
}

View File

@ -1,4 +1,4 @@
import { Dropdown, DropdownOption } from "design-system";
import { Dropdown, DropdownOption, RenderOption } from "design-system";
import React, { useEffect, useState } from "react";
import { DropdownOnSelect } from "./SelectField";
@ -21,6 +21,7 @@ type DropdownWrapperProps = {
labelRenderer?: (selected: Partial<DropdownOption>[]) => JSX.Element;
fillOptions?: boolean;
disabled?: boolean;
renderOption?: RenderOption;
};
function DropdownWrapper(props: DropdownWrapperProps) {
@ -71,6 +72,7 @@ function DropdownWrapper(props: DropdownWrapperProps) {
options={props.options}
placeholder={props.placeholder}
removeSelectedOption={onRemoveOptions}
renderOption={props?.renderOption}
selected={
props.isMultiSelect
? (props.selected as DropdownOption[])

View File

@ -11,7 +11,7 @@ import CodeEditor, {
EditorProps,
} from "components/editorComponents/CodeEditor";
import { CodeEditorBorder } from "components/editorComponents/CodeEditor/EditorConfig";
import { API_EDITOR_FORM_NAME } from "constants/forms";
import { API_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import { AppState } from "@appsmith/reducers";
import { connect } from "react-redux";
import get from "lodash/get";

View File

@ -4,7 +4,7 @@ import {
WrappedFieldMetaProps,
WrappedFieldInputProps,
} from "redux-form";
import { DropdownOption } from "design-system";
import { DropdownOption, RenderOption } from "design-system";
import DropdownWrapper from "./DropdownWrapper";
const renderComponent = (
@ -33,6 +33,7 @@ type SelectFieldProps = {
labelRenderer?: (selected: Partial<DropdownOption>[]) => JSX.Element;
fillOptions?: boolean;
disabled?: boolean;
renderOption?: RenderOption;
};
export function SelectField(props: SelectFieldProps) {
@ -50,6 +51,7 @@ export function SelectField(props: SelectFieldProps) {
outline={props.outline}
placeholder={props.placeholder}
removeSelectedOption={props.removeSelectedOption}
renderOption={props?.renderOption}
selected={props.selected}
showLabelOnly={props.showLabelOnly}
size={props.size}

View File

@ -1,4 +1,4 @@
import React from "react";
import React, { ReactElement } from "react";
import {
Field,
WrappedFieldMetaProps,
@ -23,7 +23,9 @@ type TagListFieldProps = {
type: string;
label: string;
intent: Intent;
customError: (err: string) => void;
customError: (err: string, values?: string[]) => void;
suggestions?: { id: string; name: string; icon?: string }[];
suggestionLeftIcon?: ReactElement;
};
function TagListField(props: TagListFieldProps) {

View File

@ -4,7 +4,7 @@ import { ControlType } from "constants/PropertyControlConstants";
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
import { AppState } from "@appsmith/reducers";
import { formValueSelector } from "redux-form";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
import { QUERY_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import { connect } from "react-redux";
import { actionPathFromName } from "components/formControls/utils";
import {

View File

@ -9,7 +9,7 @@ import {
EditorModes,
TabBehaviour,
} from "components/editorComponents/CodeEditor/EditorConfig";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
import { QUERY_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import { AppState } from "@appsmith/reducers";
import styled from "styled-components";
import TemplateMenu from "pages/Editor/QueryEditor/TemplateMenu";

View File

@ -1,41 +0,0 @@
export const API_EDITOR_FORM_NAME = "ApiEditorForm";
export const CREATE_APPLICATION_FORM_NAME = "CreateApplicationForm";
export const INVITE_USERS_TO_WORKSPACE_FORM = "InviteUsersToWorkspaceForm";
export const LOGIN_FORM_NAME = "LoginForm";
export const LOGIN_FORM_EMAIL_FIELD_NAME = "username";
export const LOGIN_FORM_PASSWORD_FIELD_NAME = "password";
export const SIGNUP_FORM_NAME = "SignupForm";
export const SIGNUP_FORM_EMAIL_FIELD_NAME = "email";
export const FORGOT_PASSWORD_FORM_NAME = "ForgotPasswordForm";
export const RESET_PASSWORD_FORM_NAME = "ResetPasswordForm";
export const CREATE_PASSWORD_FORM_NAME = "CreatePasswordForm";
export const CREATE_WORKSPACE_FORM_NAME = "New Workspace";
export const CURL_IMPORT_FORM = "CurlImportForm";
export const QUERY_EDITOR_FORM_NAME = "QueryEditorForm";
export const API_HOME_SCREEN_FORM = "APIHomeScreenForm";
export const SAAS_EDITOR_FORM = "SaaSEditorForm";
export const DATASOURCE_DB_FORM = "DatasourceDBForm";
export const DATASOURCE_REST_API_FORM = "DatasourceRestAPIForm";
export const DATASOURCE_SAAS_FORM = "DatasourceSaaSForm";
export const WELCOME_FORM_NAME = "WelcomeSetupForm";
export const WELCOME_FORM_NAME_FIELD_NAME = "name";
export const WELCOME_FORM_EMAIL_FIELD_NAME = "email";
export const WELCOME_FORM_PASSWORD_FIELD_NAME = "password";
export const WELCOME_FORM_VERIFY_PASSWORD_FIELD_NAME = "verify_password";
export const WELCOME_FORM_ROLE_FIELD_NAME = "role";
export const WELCOME_FORM_ROLE_NAME_FIELD_NAME = "role_name";
export const WELCOME_FORM_USECASE_FIELD_NAME = "useCase";
export const WELCOME_FORM_CUSTOM_USECASE_FIELD_NAME = "custom_useCase";
export const SETTINGS_FORM_NAME = "SettingsForm";
export const WELCOME_NON_SUPER_FORM_NAME = "WelcomeNonSuperSetupForm";
export const SAVE_THEME_FORM_NAME = "SaveThemeForm";
export const REDIRECT_URL_FORM = "RedirectURLForm";
export const ENTITYID_URL_FORM = "EntityIdURLForm";

View File

@ -0,0 +1,3 @@
export * from "ce/pages/workspace/WorkspaceInviteUsersForm";
import { default as CE_Workspace_Invite_Users_Form } from "ce/pages/workspace/WorkspaceInviteUsersForm";
export default CE_Workspace_Invite_Users_Form;

View File

@ -0,0 +1 @@
export * from "ce/pages/workspace/helpers";

View File

@ -0,0 +1,3 @@
export * from "ce/reducers/uiReducers/applicationsReducer";
import { default as CE_Applications_Reducer } from "ce/reducers/uiReducers/applicationsReducer";
export default CE_Applications_Reducer;

View File

@ -4,6 +4,7 @@ import {
FetchAdminSettingsErrorSaga,
SaveAdminSettingsSaga,
RestartServerPoll,
RestryRestartServerPoll,
SendTestEmail,
} from "ce/sagas/SuperUserSagas";
import {
@ -24,6 +25,10 @@ export function* InitSuperUserSaga(action: ReduxAction<User>) {
),
takeLatest(ReduxActionTypes.SAVE_ADMIN_SETTINGS, SaveAdminSettingsSaga),
takeLatest(ReduxActionTypes.RESTART_SERVER_POLL, RestartServerPoll),
takeLatest(
ReduxActionTypes.RETRY_RESTART_SERVER_POLL,
RestryRestartServerPoll,
),
takeLatest(ReduxActionTypes.SEND_TEST_EMAIL, SendTestEmail),
]);
}

View File

@ -0,0 +1,52 @@
export * from "ce/sagas/userSagas";
import {
createUserSaga,
getCurrentUserSaga,
forgotPasswordSaga,
resetPasswordSaga,
verifyResetPasswordTokenSaga,
inviteUsers,
logoutSaga,
verifyUserInviteSaga,
invitedUserSignupSaga,
updateUserDetailsSaga,
removePhoto,
updatePhoto,
leaveWorkspaceSaga,
fetchFeatureFlags,
updateFirstTimeUserOnboardingSage,
} from "ce/sagas/userSagas";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { takeLatest, all } from "redux-saga/effects";
export default function* userSagas() {
yield all([
takeLatest(ReduxActionTypes.CREATE_USER_INIT, createUserSaga),
takeLatest(ReduxActionTypes.FETCH_USER_INIT, getCurrentUserSaga),
takeLatest(ReduxActionTypes.FORGOT_PASSWORD_INIT, forgotPasswordSaga),
takeLatest(ReduxActionTypes.RESET_USER_PASSWORD_INIT, resetPasswordSaga),
takeLatest(
ReduxActionTypes.RESET_PASSWORD_VERIFY_TOKEN_INIT,
verifyResetPasswordTokenSaga,
),
takeLatest(ReduxActionTypes.INVITE_USERS_TO_WORKSPACE_INIT, inviteUsers),
takeLatest(ReduxActionTypes.LOGOUT_USER_INIT, logoutSaga),
takeLatest(ReduxActionTypes.VERIFY_INVITE_INIT, verifyUserInviteSaga),
takeLatest(
ReduxActionTypes.INVITED_USER_SIGNUP_INIT,
invitedUserSignupSaga,
),
takeLatest(
ReduxActionTypes.UPDATE_USER_DETAILS_INIT,
updateUserDetailsSaga,
),
takeLatest(ReduxActionTypes.REMOVE_PROFILE_PHOTO, removePhoto),
takeLatest(ReduxActionTypes.UPLOAD_PROFILE_PHOTO, updatePhoto),
takeLatest(ReduxActionTypes.LEAVE_WORKSPACE_INIT, leaveWorkspaceSaga),
takeLatest(ReduxActionTypes.FETCH_FEATURE_FLAGS_INIT, fetchFeatureFlags),
takeLatest(
ReduxActionTypes.FETCH_USER_DETAILS_SUCCESS,
updateFirstTimeUserOnboardingSage,
),
]);
}

View File

@ -29,7 +29,7 @@ import {
ApplicationPayload,
ReduxActionErrorTypes,
ReduxActionTypes,
} from "ce/constants/ReduxActionConstants";
} from "@appsmith/constants/ReduxActionConstants";
import { addBranchParam } from "constants/routes";
import { APP_MODE } from "entities/App";
import { all, call, put, select } from "redux-saga/effects";

View File

@ -15,7 +15,7 @@ import {
import {
ReduxActionErrorTypes,
ReduxActionTypes,
} from "ce/constants/ReduxActionConstants";
} from "@appsmith/constants/ReduxActionConstants";
import { APP_MODE } from "entities/App";
import { call, put } from "redux-saga/effects";
import { failFastApiCalls } from "sagas/InitSagas";

View File

@ -4,7 +4,7 @@ import {
ApplicationPayload,
ReduxActionErrorTypes,
ReduxActionTypes,
} from "ce/constants/ReduxActionConstants";
} from "@appsmith/constants/ReduxActionConstants";
import { getPersistentAppStore } from "constants/AppConstants";
import { APP_MODE } from "entities/App";
import log from "loglevel";

View File

@ -1,5 +1,5 @@
import { ApplicationVersion } from "actions/applicationActions";
import { ApplicationPayload } from "ce/constants/ReduxActionConstants";
import { ApplicationPayload } from "@appsmith/constants/ReduxActionConstants";
import { APP_MODE } from "entities/App";
import { select } from "redux-saga/effects";
import { builderURL } from "RouteBuilder";

View File

@ -1,4 +1,7 @@
import { ApplicationPayload, Page } from "ce/constants/ReduxActionConstants";
import {
ApplicationPayload,
Page,
} from "@appsmith/constants/ReduxActionConstants";
import { APP_MODE } from "entities/App";
import { select } from "redux-saga/effects";
import { fillPathname, viewerURL } from "RouteBuilder";

View File

@ -34,6 +34,12 @@ import BackToHomeButton from "./BackToHomeButton";
import TourCompletionMessage from "pages/Editor/GuidedTour/TourCompletionMessage";
import { useHref } from "pages/Editor/utils";
import { builderURL } from "RouteBuilder";
import { inviteModalLinks } from "@appsmith/constants/forms";
import {
createMessage,
INVITE_USERS_MESSAGE,
INVITE_USERS_PLACEHOLDER,
} from "@appsmith/constants/messages";
/**
* ----------------------------------------------------------------------------
@ -129,6 +135,9 @@ export function AppViewerHeader(props: AppViewerHeaderProps) {
bgColor: "transparent",
}}
isOpen={showAppInviteUsersDialog}
links={inviteModalLinks}
message={createMessage(INVITE_USERS_MESSAGE)}
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
title={currentApplicationDetails.name}
trigger={
<Button

View File

@ -24,6 +24,12 @@ import { useHref } from "pages/Editor/utils";
import { APP_MODE } from "entities/App";
import { builderURL, viewerURL } from "RouteBuilder";
import { trimQueryString } from "utils/helpers";
import { inviteModalLinks } from "@appsmith/constants/forms";
import {
createMessage,
INVITE_USERS_MESSAGE,
INVITE_USERS_PLACEHOLDER,
} from "@appsmith/constants/messages";
type AppViewerHeaderProps = {
isOpen?: boolean;
@ -112,6 +118,9 @@ export function PageMenu(props: AppViewerHeaderProps) {
bgColor: "transparent",
}}
isOpen={showAppInviteUsersDialog}
links={inviteModalLinks}
message={createMessage(INVITE_USERS_MESSAGE)}
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
title={application.name}
trigger={
<Button

View File

@ -1,7 +1,7 @@
import React from "react";
import { connect } from "react-redux";
import { Form, reduxForm, InjectedFormProps, Field } from "redux-form";
import { CREATE_APPLICATION_FORM_NAME } from "constants/forms";
import { CREATE_APPLICATION_FORM_NAME } from "@appsmith/constants/forms";
import {
createMessage,
ERROR_MESSAGE_NAME_EMPTY,

View File

@ -35,13 +35,16 @@ import {
import PageWrapper from "pages/common/PageWrapper";
import SubHeader from "pages/common/SubHeader";
import ApplicationCard from "./ApplicationCard";
import WorkspaceInviteUsersForm from "pages/workspace/WorkspaceInviteUsersForm";
import WorkspaceInviteUsersForm from "@appsmith/pages/workspace/WorkspaceInviteUsersForm";
import { isPermitted, PERMISSION_TYPE } from "./permissionHelpers";
import FormDialogComponent from "components/editorComponents/form/FormDialogComponent";
import Dialog from "components/ads/DialogComponent";
import { User } from "constants/userConstants";
import { getCurrentUser, selectFeatureFlags } from "selectors/usersSelectors";
import { CREATE_WORKSPACE_FORM_NAME } from "constants/forms";
import {
CREATE_WORKSPACE_FORM_NAME,
inviteModalLinks,
} from "@appsmith/constants/forms";
import {
DropdownOnSelectActions,
getOnSelectAction,
@ -70,7 +73,7 @@ import PerformanceTracker, {
PerformanceTransactionName,
} from "utils/PerformanceTracker";
import { loadingUserWorkspaces } from "./ApplicationLoaders";
import { creatingApplicationMap } from "reducers/uiReducers/applicationsReducer";
import { creatingApplicationMap } from "@appsmith/reducers/uiReducers/applicationsReducer";
import EditableText, {
EditInteractionKind,
SavingState,
@ -81,13 +84,15 @@ import { leaveWorkspace } from "actions/userActions";
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
import NoSearchImage from "assets/images/NoSearchResult.svg";
import { getNextEntityName, getRandomPaletteColor } from "utils/AppsmithUtils";
import { createWorkspaceSubmitHandler } from "pages/workspace/helpers";
import { createWorkspaceSubmitHandler } from "@appsmith/pages/workspace/helpers";
import ImportApplicationModal from "./ImportApplicationModal";
import {
createMessage,
NO_APPS_FOUND,
WORKSPACES_HEADING,
SEARCH_APPS,
INVITE_USERS_MESSAGE,
INVITE_USERS_PLACEHOLDER,
} from "@appsmith/constants/messages";
import { ReactComponent as NoAppsFoundIcon } from "assets/svg/no-apps-icon.svg";
@ -702,7 +707,11 @@ function ApplicationsSection(props: any) {
onClose={() => setSelectedWorkspaceId("")}
title={`Invite Users to ${workspace.name}`}
>
<Form workspaceId={workspace.id} />
<Form
links={inviteModalLinks}
message={createMessage(INVITE_USERS_MESSAGE)}
workspaceId={workspace.id}
/>
</Dialog>
)}
{selectedWorkspaceIdForImportApplication && (
@ -725,6 +734,9 @@ function ApplicationsSection(props: any) {
<FormDialogComponent
Form={WorkspaceInviteUsersForm}
canOutsideClickClose
links={inviteModalLinks}
message={createMessage(INVITE_USERS_MESSAGE)}
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
title={`Invite Users to ${workspace.name}`}
trigger={
<Button

View File

@ -11,7 +11,7 @@ import {
import history from "utils/history";
import { getQueryParams } from "utils/URLUtils";
import { AuthType } from "entities/Datasource/RestAPIForm";
import { API_EDITOR_FORM_NAME } from "constants/forms";
import { API_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import { formValueSelector } from "redux-form";
import { AppState } from "@appsmith/reducers";
import { ReactComponent as SheildSuccess } from "assets/icons/ads/shield-success.svg";

View File

@ -5,7 +5,7 @@ import { withRouter, RouteComponentProps } from "react-router";
import styled from "styled-components";
import { AppState } from "@appsmith/reducers";
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
import { CURL_IMPORT_FORM } from "constants/forms";
import { CURL_IMPORT_FORM } from "@appsmith/constants/forms";
import { BuilderRouteParams } from "constants/routes";
import { curlImportFormValues, curlImportSubmitHandler } from "./helpers";
import { createNewApiName } from "utils/AppsmithUtils";

View File

@ -14,7 +14,7 @@ import styled from "styled-components";
import FormLabel from "components/editorComponents/FormLabel";
import FormRow from "components/editorComponents/FormRow";
import { PaginationField, SuggestedWidget } from "api/ActionAPI";
import { API_EDITOR_FORM_NAME } from "constants/forms";
import { API_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import Pagination from "./Pagination";
import { Action, PaginationType } from "entities/Action";
import {

View File

@ -6,7 +6,7 @@ import {
POST_BODY_FORMAT_OPTIONS,
POST_BODY_FORMAT_TITLES,
} from "constants/ApiEditorConstants";
import { API_EDITOR_FORM_NAME } from "constants/forms";
import { API_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
import { AppState } from "@appsmith/reducers";

View File

@ -9,7 +9,7 @@ import { PaginationField, BodyFormData, Property } from "api/ActionAPI";
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
import ApiResponseView from "components/editorComponents/ApiResponseView";
import { API_EDITOR_FORM_NAME } from "constants/forms";
import { API_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import CredentialsTooltip from "components/editorComponents/form/CredentialsTooltip";
import { FormIcons } from "icons/FormIcons";
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";

View File

@ -2,7 +2,7 @@ import React from "react";
import { connect } from "react-redux";
import styled from "styled-components";
import _ from "lodash";
import { DATASOURCE_DB_FORM } from "constants/forms";
import { DATASOURCE_DB_FORM } from "@appsmith/constants/forms";
import { Icon } from "@blueprintjs/core";
import FormTitle from "./FormTitle";
import { Button, Category } from "design-system";

View File

@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import { createNewApiName } from "utils/AppsmithUtils";
import { DATASOURCE_REST_API_FORM } from "constants/forms";
import { DATASOURCE_REST_API_FORM } from "@appsmith/constants/forms";
import FormTitle from "./FormTitle";
import Button from "components/editorComponents/Button";
import { Datasource } from "entities/Datasource";

View File

@ -12,7 +12,7 @@ import {
switchDatasource,
setDatsourceEditorMode,
} from "actions/datasourceActions";
import { DATASOURCE_DB_FORM } from "constants/forms";
import { DATASOURCE_DB_FORM } from "@appsmith/constants/forms";
import DataSourceEditorForm from "./DBForm";
import RestAPIDatasourceForm from "./RestAPIDatasourceForm";
import { Datasource } from "entities/Datasource";
@ -33,7 +33,7 @@ import {
REST_API_AUTHORIZATION_APPSMITH_ERROR,
REST_API_AUTHORIZATION_FAILED,
REST_API_AUTHORIZATION_SUCCESSFUL,
} from "ce/constants/messages";
} from "@appsmith/constants/messages";
import { Toaster } from "components/ads/Toast";
import { Variant } from "components/ads/common";

View File

@ -61,6 +61,8 @@ import {
CLOSE_ENTITY_EXPLORER_MESSAGE,
createMessage,
DEPLOY_BUTTON_TOOLTIP,
INVITE_USERS_MESSAGE,
INVITE_USERS_PLACEHOLDER,
LOCK_ENTITY_EXPLORER_MESSAGE,
LOGO_TOOLTIP,
RENAME_APPLICATION_TOOLTIP,
@ -82,6 +84,7 @@ import EndTour from "./GuidedTour/EndTour";
import { GUIDED_TOUR_STEPS } from "./GuidedTour/constants";
import { viewerURL } from "RouteBuilder";
import { useHref } from "./utils";
import { inviteModalLinks } from "@appsmith/constants/forms";
const HeaderWrapper = styled.div`
width: 100%;
@ -459,6 +462,9 @@ export function EditorHeader(props: EditorHeaderProps) {
bgColor: Colors.GEYSER_LIGHT,
}}
isOpen={showAppInviteUsersDialog}
links={inviteModalLinks}
message={createMessage(INVITE_USERS_MESSAGE)}
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
title={
currentApplication
? currentApplication.name

View File

@ -22,7 +22,10 @@ import { Colors } from "constants/Colors";
import { TOOLTIP_HOVER_ON_DELAY } from "constants/AppConstants";
import { EntityClassNames } from "../Entity";
import { TooltipComponent } from "design-system";
import { ADD_QUERY_JS_BUTTON, createMessage } from "ce/constants/messages";
import {
ADD_QUERY_JS_BUTTON,
createMessage,
} from "@appsmith/constants/messages";
import { useCloseMenuOnScroll } from "../hooks";
import { SIDEBAR_ID } from "constants/Explorer";

View File

@ -4,7 +4,7 @@ import { connect } from "react-redux";
import { initialize } from "redux-form";
import { getDBPlugins, getPluginImages } from "selectors/entitiesSelector";
import { Plugin } from "api/PluginApi";
import { DATASOURCE_DB_FORM } from "constants/forms";
import { DATASOURCE_DB_FORM } from "@appsmith/constants/forms";
import { createDatasourceFromForm } from "actions/datasourceActions";
import { AppState } from "@appsmith/reducers";
import AnalyticsUtil from "utils/AnalyticsUtil";

View File

@ -3,7 +3,7 @@ import { connect } from "react-redux";
import { reduxForm, InjectedFormProps } from "redux-form";
import styled from "styled-components";
import { AppState } from "@appsmith/reducers";
import { API_HOME_SCREEN_FORM } from "constants/forms";
import { API_HOME_SCREEN_FORM } from "@appsmith/constants/forms";
import { Colors } from "constants/Colors";
import { TabComponent, TabProp } from "components/ads/Tabs";
import { IconSize } from "design-system";

View File

@ -11,7 +11,10 @@ import {
StyledButton,
TooltipComponent as Tooltip,
} from "design-system";
import { createMessage, NO_JS_FUNCTION_TO_RUN } from "ce/constants/messages";
import {
createMessage,
NO_JS_FUNCTION_TO_RUN,
} from "@appsmith/constants/messages";
import { JSActionDropdownOption } from "./utils";
import { RUN_BUTTON_DEFAULTS, testLocators } from "./constants";

View File

@ -3,7 +3,7 @@ import {
ASYNC_FUNCTION_SETTINGS_HEADING,
createMessage,
NO_ASYNC_FUNCTIONS,
} from "ce/constants/messages";
} from "@appsmith/constants/messages";
import {
AppIcon,
Radio,

View File

@ -1,5 +1,5 @@
import { all } from "@redux-saga/core/effects";
import { AppState } from "ce/reducers";
import { AppState } from "@appsmith/reducers";
import lodash from "lodash";
import React from "react";
import { MemoryRouter } from "react-router-dom";

View File

@ -1,7 +1,7 @@
import React from "react";
import { IconNames } from "@blueprintjs/icons";
import { Icon, IconSize } from "design-system";
import { PROPERTY_PANE_EMPTY_SEARCH_RESULT_MESSAGE } from "ce/constants/messages";
import { PROPERTY_PANE_EMPTY_SEARCH_RESULT_MESSAGE } from "@appsmith/constants/messages";
import styled from "styled-components";
import { Colors } from "constants/Colors";

View File

@ -1,5 +1,5 @@
import { formValueSelector, reduxForm } from "redux-form";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
import { QUERY_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import { Action } from "entities/Action";
import { connect } from "react-redux";
import { AppState } from "@appsmith/reducers";

View File

@ -18,7 +18,7 @@ import {
getCurrentApplicationId,
getIsEditorInitialized,
} from "selectors/editorSelectors";
import { QUERY_EDITOR_FORM_NAME } from "constants/forms";
import { QUERY_EDITOR_FORM_NAME } from "@appsmith/constants/forms";
import { Plugin, UIComponentTypes } from "api/PluginApi";
import { Datasource } from "entities/Datasource";
import {

View File

@ -1,7 +1,7 @@
import React from "react";
import styled from "styled-components";
import _, { merge } from "lodash";
import { DATASOURCE_SAAS_FORM } from "constants/forms";
import { DATASOURCE_SAAS_FORM } from "@appsmith/constants/forms";
import FormTitle from "pages/Editor/DataSourceEditor/FormTitle";
import { Button as AdsButton, Category } from "design-system";
import { Datasource } from "entities/Datasource";

View File

@ -13,7 +13,7 @@ import {
ERROR_MESSAGE_NAME_EMPTY,
APLHANUMERIC_HYPHEN_SLASH_SPACE_ERROR,
UNIQUE_NAME_ERROR,
} from "ce/constants/messages";
} from "@appsmith/constants/messages";
interface SaveThemeModalProps {
isOpen: boolean;

View File

@ -5,7 +5,7 @@ import {
SettingSubtype,
} from "@appsmith/pages/AdminSettings/config/types";
import Accordion from "./Accordion";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import { reduxForm } from "redux-form";
let container: any = null;

View File

@ -1,4 +1,4 @@
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import React from "react";
import { Button, Category } from "design-system";
import { useDispatch } from "react-redux";

View File

@ -10,7 +10,7 @@ import { FormGroup, SettingComponentProps } from "./Common";
import { FormTextFieldProps } from "components/ads/formFields/TextField";
import { Button, Category, Checkbox } from "design-system";
import { useSelector } from "react-redux";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import useOnUpgrade from "utils/hooks/useOnUpgrade";
import { EventName } from "utils/AnalyticsUtil";

View File

@ -2,7 +2,7 @@ import { render, screen } from "test/testUtils";
import React from "react";
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
import Group from "./group";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import { reduxForm } from "redux-form";
let container: any = null;

View File

@ -2,7 +2,7 @@ import { render, screen } from "test/testUtils";
import React from "react";
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
import TagInputField from "./TagInputField";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import { reduxForm } from "redux-form";
let container: any = null;

View File

@ -5,7 +5,7 @@ import {
SettingSubtype,
} from "@appsmith/pages/AdminSettings/config/types";
import TextInput from "./TextInput";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import { reduxForm } from "redux-form";
let container: any = null;

View File

@ -2,7 +2,7 @@ import { render } from "test/testUtils";
import React from "react";
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
import Toggle from "./Toggle";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import { reduxForm } from "redux-form";
let container: any = null;

View File

@ -10,7 +10,7 @@ import Toggle from "./Toggle";
import Text from "./Text";
import Button from "./Button";
import { getFormValues } from "redux-form";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import { useSelector } from "store";
import {
createMessage,

View File

@ -1,6 +1,6 @@
import React, { useCallback, useEffect } from "react";
import { saveSettings } from "@appsmith/actions/settingsAction";
import { SETTINGS_FORM_NAME } from "constants/forms";
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import _ from "lodash";
import ProductUpdatesModal from "pages/Applications/ProductUpdatesModal";

View File

@ -29,7 +29,7 @@ import {
} from "@appsmith/constants/messages";
import { AUTH_LOGIN_URL } from "constants/routes";
import FormMessage from "components/ads/formFields/FormMessage";
import { FORGOT_PASSWORD_FORM_NAME } from "constants/forms";
import { FORGOT_PASSWORD_FORM_NAME } from "@appsmith/constants/forms";
import FormGroup from "components/ads/formFields/FormGroup";
import { Button, Size } from "design-system";
import FormTextField from "components/ads/formFields/TextField";

View File

@ -3,7 +3,7 @@ import { AppState } from "@appsmith/reducers";
import { withRouter, RouteComponentProps } from "react-router-dom";
import { connect } from "react-redux";
import { InjectedFormProps, reduxForm, Field } from "redux-form";
import { RESET_PASSWORD_FORM_NAME } from "constants/forms";
import { RESET_PASSWORD_FORM_NAME } from "@appsmith/constants/forms";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { getIsTokenValid, getIsValidatingToken } from "selectors/authSelectors";
import { Icon } from "@blueprintjs/core";

View File

@ -7,7 +7,7 @@ import {
WELCOME_FORM_ROLE_NAME_FIELD_NAME,
WELCOME_FORM_USECASE_FIELD_NAME,
WELCOME_NON_SUPER_FORM_NAME,
} from "constants/forms";
} from "@appsmith/constants/forms";
import {
createMessage,
WELCOME_ACTION,

View File

@ -15,7 +15,7 @@ import {
WELCOME_FORM_ROLE_NAME_FIELD_NAME,
WELCOME_FORM_VERIFY_PASSWORD_FIELD_NAME,
WELCOME_FORM_CUSTOM_USECASE_FIELD_NAME,
} from "constants/forms";
} from "@appsmith/constants/forms";
import {
FormErrors,
formValueSelector,

View File

@ -11,7 +11,7 @@ import {
} from "../Applications/permissionHelpers";
import WorkspaceInviteUsersForm, {
InviteButtonWidth,
} from "./WorkspaceInviteUsersForm";
} from "@appsmith/pages/workspace/WorkspaceInviteUsersForm";
import { getCurrentUser } from "selectors/usersSelectors";
import { Text, TextType, Toggle } from "design-system";
import { ANONYMOUS_USERNAME } from "constants/userConstants";
@ -63,6 +63,7 @@ function AppInviteUsersForm(props: any) {
fetchCurrentWorkspace,
isChangingViewAccess,
isFetchingApplication,
links,
} = props;
const currentWorkspaceId = useSelector(getCurrentWorkspaceId);
@ -124,6 +125,7 @@ function AppInviteUsersForm(props: any) {
{canInviteToWorkspace && (
<WorkspaceInviteUsersForm
isApplicationInvite
links={links}
workspaceId={props.workspaceId}
/>
)}

View File

@ -1,10 +1,10 @@
import React, { useCallback } from "react";
import { Form, reduxForm, InjectedFormProps } from "redux-form";
import { CREATE_WORKSPACE_FORM_NAME } from "constants/forms";
import { CREATE_WORKSPACE_FORM_NAME } from "@appsmith/constants/forms";
import {
CreateWorkspaceFormValues,
createWorkspaceSubmitHandler,
} from "./helpers";
} from "@appsmith/pages/workspace/helpers";
import { noSpaces } from "utils/formhelpers";
import TextField from "components/editorComponents/form/fields/TextField";
import FormGroup from "components/editorComponents/form/FormGroup";

View File

@ -1,493 +0,0 @@
import React, { Fragment, useContext, useEffect, useState } from "react";
import styled, {
createGlobalStyle,
css,
ThemeContext,
} from "styled-components";
import TagListField from "components/editorComponents/form/fields/TagListField";
import { reduxForm, SubmissionError } from "redux-form";
import SelectField from "components/editorComponents/form/fields/SelectField";
import { connect, useSelector } from "react-redux";
import { AppState } from "@appsmith/reducers";
import {
getRolesForField,
getAllUsers,
getCurrentAppWorkspace,
} from "@appsmith/selectors/workspaceSelectors";
import Spinner from "components/editorComponents/Spinner";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import {
InviteUsersToWorkspaceFormValues,
inviteUsersToWorkspace,
} from "./helpers";
import { INVITE_USERS_TO_WORKSPACE_FORM } from "constants/forms";
import {
createMessage,
INVITE_USERS_SUBMIT_SUCCESS,
INVITE_USER_SUBMIT_SUCCESS,
INVITE_USERS_VALIDATION_EMAILS_EMPTY,
INVITE_USERS_VALIDATION_EMAIL_LIST,
INVITE_USERS_VALIDATION_ROLE_EMPTY,
} from "@appsmith/constants/messages";
import { isEmail } from "utils/formhelpers";
import {
isPermitted,
PERMISSION_TYPE,
} from "../Applications/permissionHelpers";
import { getAppsmithConfigs } from "@appsmith/configs";
import { ReactComponent as NoEmailConfigImage } from "assets/images/email-not-configured.svg";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { Button, Size, Text, TextType } from "design-system";
import { Classes, Variant } from "components/ads/common";
import Callout from "components/ads/Callout";
import { getInitialsAndColorCode } from "utils/AppsmithUtils";
import ProfileImage from "pages/common/ProfileImage";
import ManageUsers from "./ManageUsers";
import { ScrollIndicator } from "design-system";
import UserApi from "@appsmith/api/UserApi";
import { Colors } from "constants/Colors";
import { fetchWorkspace } from "actions/workspaceActions";
const CommonTitleTextStyle = css`
color: ${Colors.CHARCOAL};
font-weight: normal;
`;
const WorkspaceInviteWrapper = styled.div``;
const WorkspaceInviteTitle = styled.div`
padding: 0 0 10px 0;
& > span[type="h5"] {
${CommonTitleTextStyle}
}
`;
const StyledForm = styled.form`
width: 100%;
background: ${(props) => props.theme.colors.modal.bg};
&&& {
.wrapper > div:nth-child(1) {
width: 60%;
}
.wrapper > div:nth-child(2) {
width: 40%;
}
.bp3-input {
box-shadow: none;
}
.bp3-button {
padding-top: 5px;
}
}
`;
const ErrorBox = styled.div<{ message?: boolean }>`
${(props) =>
props.message ? `margin: ${props.theme.spaces[9]}px 0px` : null};
`;
const StyledInviteFieldGroup = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
.wrapper {
display: flex;
width: 85%;
flex-direction: row;
align-items: center;
justify-content: space-between;
margin-right: ${(props) => props.theme.spaces[3]}px;
border-right: 0px;
}
`;
const InviteModalStyles = createGlobalStyle`
.label-container > * {
word-break: break-word;
}
`;
const UserList = styled.div`
margin-top: 24px;
max-height: 260px;
overflow-y: auto;
&&::-webkit-scrollbar-thumb {
background-color: ${(props) => props.theme.colors.modal.scrollbar};
}
`;
const User = styled.div`
display: flex;
align-items: center;
min-height: 54px;
padding: 5px 0 5px 15px;
justify-content: space-between;
color: ${(props) => props.theme.colors.modal.user.textColor};
`;
const UserInfo = styled.div`
display: inline-flex;
align-items: center;
div:first-child {
cursor: default;
}
`;
const UserRole = styled.div`
flex-basis: 40%;
flex-shrink: 0;
.${Classes.TEXT} {
color: ${Colors.COD_GRAY};
display: inline-block;
width: 100%;
word-break: break-word;
}
`;
const UserName = styled.div`
display: flex;
flex-direction: column;
margin: 0 10px;
span {
word-break: break-word;
&:nth-child(1) {
margin-bottom: 1px;
}
&[type="h5"] {
color: ${Colors.COD_GRAY};
}
&[type="p2"] {
color: ${Colors.GRAY};
}
}
`;
const RoleDivider = styled.div`
border-top: 1px solid ${(props) => props.theme.colors.menuBorder};
`;
const Loading = styled(Spinner)`
padding-top: 10px;
margin: auto;
width: 100%;
`;
const MailConfigContainer = styled.div`
display: flex;
flex-direction: column;
padding: 24px 4px;
padding-bottom: 0;
align-items: center;
&& > span {
color: ${(props) => props.theme.colors.modal.email.message};
font-weight: 500;
font-size: 14px;
}
&& > a {
color: ${(props) => props.theme.colors.modal.email.desc};
font-size: 12px;
text-decoration: underline;
}
`;
const validateFormValues = (values: { users: string; role: string }) => {
if (values.users && values.users.length > 0) {
const _users = values.users.split(",").filter(Boolean);
_users.forEach((user) => {
if (!isEmail(user)) {
throw new SubmissionError({
_error: createMessage(INVITE_USERS_VALIDATION_EMAIL_LIST),
});
}
});
} else {
throw new SubmissionError({
_error: createMessage(INVITE_USERS_VALIDATION_EMAILS_EMPTY),
});
}
if (values.role === undefined || values.role?.trim().length === 0) {
throw new SubmissionError({
_error: createMessage(INVITE_USERS_VALIDATION_ROLE_EMPTY),
});
}
};
const validate = (values: any) => {
const errors: any = {};
if (!(values.users && values.users.length > 0)) {
errors["users"] = createMessage(INVITE_USERS_VALIDATION_EMAILS_EMPTY);
}
if (values.role === undefined || values.role?.trim().length === 0) {
errors["role"] = createMessage(INVITE_USERS_VALIDATION_ROLE_EMPTY);
}
if (values.users && values.users.length > 0) {
const _users = values.users.split(",").filter(Boolean);
_users.forEach((user: string) => {
if (!isEmail(user)) {
errors["users"] = createMessage(INVITE_USERS_VALIDATION_EMAIL_LIST);
}
});
}
return errors;
};
const { mailEnabled } = getAppsmithConfigs();
export const InviteButtonWidth = "88px";
function WorkspaceInviteUsersForm(props: any) {
const [emailError, setEmailError] = useState("");
const [selectedOption, setSelectedOption] = useState<any>({});
const userRef = React.createRef<HTMLDivElement>();
const {
allUsers,
anyTouched,
error,
fetchAllRoles,
fetchCurrentWorkspace,
fetchUser,
handleSubmit,
isApplicationInvite,
isLoading,
submitFailed,
submitSucceeded,
submitting,
valid,
} = props;
// set state for checking number of users invited
const [numberOfUsersInvited, updateNumberOfUsersInvited] = useState(0);
const currentWorkspace = useSelector(getCurrentAppWorkspace);
const userWorkspacePermissions = currentWorkspace?.userPermissions ?? [];
const canManage = isPermitted(
userWorkspacePermissions,
PERMISSION_TYPE.MANAGE_WORKSPACE,
);
useEffect(() => {
fetchUser(props.workspaceId);
fetchAllRoles(props.workspaceId);
fetchCurrentWorkspace(props.workspaceId);
}, [props.workspaceId, fetchUser, fetchAllRoles, fetchCurrentWorkspace]);
const styledRoles = props.roles.map((role: any) => {
return {
id: role.id,
value: role.name,
label: role.description,
};
});
const theme = useContext(ThemeContext);
const allUsersProfiles = React.useMemo(
() =>
allUsers.map(
(user: {
userId: string;
username: string;
permissionGroupId: string;
permissionGroupName: string;
name: string;
}) => {
const details = getInitialsAndColorCode(
user.name || user.username,
theme.colors.appCardColors,
);
return {
...user,
initials: details[0],
};
},
),
[allUsers, theme],
);
return (
<WorkspaceInviteWrapper>
<InviteModalStyles />
{isApplicationInvite && (
<WorkspaceInviteTitle>
<Text type={TextType.H5}>
Invite users to {currentWorkspace?.name}{" "}
</Text>
</WorkspaceInviteTitle>
)}
<StyledForm
onSubmit={handleSubmit((values: any, dispatch: any) => {
validateFormValues(values);
AnalyticsUtil.logEvent("INVITE_USER", values);
const usersAsStringsArray = values.users.split(",");
// update state to show success message correctly
updateNumberOfUsersInvited(usersAsStringsArray.length);
return inviteUsersToWorkspace(
{
...values,
permissionGroupId: selectedOption.id,
workspaceId: props.workspaceId,
},
dispatch,
);
})}
>
<StyledInviteFieldGroup>
<div className="wrapper">
<TagListField
autofocus
customError={(err: string) => setEmailError(err)}
data-cy="t--invite-email-input"
intent="success"
label="Emails"
name="users"
placeholder="Enter email address"
type="email"
/>
<SelectField
data-cy="t--invite-role-input"
name="role"
onSelect={(value, option) => setSelectedOption(option)}
options={styledRoles}
outline={false}
placeholder="Select a role"
size="small"
/>
</div>
<Button
className="t--invite-user-btn"
disabled={!valid}
isLoading={submitting && !(submitFailed && !anyTouched)}
size={Size.large}
tag="button"
text="Invite"
variant={Variant.info}
width={InviteButtonWidth}
/>
</StyledInviteFieldGroup>
{isLoading ? (
<Loading size={30} />
) : (
<>
{!mailEnabled && (
<MailConfigContainer>
{allUsers.length === 0 && <NoEmailConfigImage />}
<span>You havent setup any email service yet</span>
<a
href="https://docs.appsmith.com/v/v1.2.1/setup/docker/email"
rel="noopener noreferrer"
target="_blank"
>
Please configure your email service to invite people
</a>
</MailConfigContainer>
)}
<UserList ref={userRef} style={{ justifyContent: "space-between" }}>
{allUsersProfiles.map(
(user: {
username: string;
name: string;
permissionGroupId: string;
permissionGroupName: string;
initials: string;
}) => {
return (
<Fragment key={user.username}>
<User>
<UserInfo>
<ProfileImage
source={`/api/${UserApi.photoURL}/${user.username}`}
userName={user.name || user.username}
/>
<UserName>
<Text type={TextType.H5}>{user.name}</Text>
<Text type={TextType.P2}>{user.username}</Text>
</UserName>
</UserInfo>
<UserRole>
<Text type={TextType.P1}>
{user.permissionGroupName}
</Text>
</UserRole>
</User>
<RoleDivider />
</Fragment>
);
},
)}
<ScrollIndicator containerRef={userRef} mode="DARK" />
</UserList>
</>
)}
<ErrorBox message={submitSucceeded || submitFailed}>
{submitSucceeded && (
<Callout
fill
text={
numberOfUsersInvited > 1
? createMessage(INVITE_USERS_SUBMIT_SUCCESS)
: createMessage(INVITE_USER_SUBMIT_SUCCESS)
}
variant={Variant.success}
/>
)}
{((submitFailed && error) || emailError) && (
<Callout fill text={error || emailError} variant={Variant.danger} />
)}
</ErrorBox>
{canManage && <ManageUsers workspaceId={props.workspaceId} />}
</StyledForm>
</WorkspaceInviteWrapper>
);
}
export default connect(
(state: AppState) => {
return {
roles: getRolesForField(state),
allUsers: getAllUsers(state),
isLoading: state.ui.workspaces.loadingStates.isFetchAllUsers,
};
},
(dispatch: any) => ({
fetchAllRoles: (workspaceId: string) =>
dispatch({
type: ReduxActionTypes.FETCH_ALL_ROLES_INIT,
payload: {
workspaceId,
},
}),
fetchCurrentWorkspace: (workspaceId: string) =>
dispatch(fetchWorkspace(workspaceId)),
fetchUser: (workspaceId: string) =>
dispatch({
type: ReduxActionTypes.FETCH_ALL_USERS_INIT,
payload: {
workspaceId,
},
}),
}),
)(
reduxForm<
InviteUsersToWorkspaceFormValues,
{
fetchAllRoles: (workspaceId: string) => void;
roles?: any;
applicationId?: string;
workspaceId?: string;
isApplicationInvite?: boolean;
}
>({
validate,
form: INVITE_USERS_TO_WORKSPACE_FORM,
})(WorkspaceInviteUsersForm),
);

View File

@ -20,9 +20,9 @@ import { useMediaQuery } from "react-responsive";
import { BackButton, StickyHeader } from "components/utils/helperComponents";
import { debounce } from "lodash";
import FormDialogComponent from "components/editorComponents/form/FormDialogComponent";
import WorkspaceInviteUsersForm from "./WorkspaceInviteUsersForm";
import WorkspaceInviteUsersForm from "@appsmith/pages/workspace/WorkspaceInviteUsersForm";
import { SettingsPageHeader } from "./SettingsPageHeader";
import { navigateToTab } from "./helpers";
import { navigateToTab } from "@appsmith/pages/workspace/helpers";
const SentryRoute = Sentry.withSentryRouting(Route);

View File

@ -4,7 +4,7 @@ import {
ReduxActionTypes,
ReduxAction,
ReduxActionErrorTypes,
} from "ce/constants/ReduxActionConstants";
} from "@appsmith/constants/ReduxActionConstants";
import { set, keyBy, findIndex, unset } from "lodash";
import produce from "immer";

View File

@ -3,7 +3,7 @@ import editorReducer from "./editorReducer";
import errorReducer from "./errorReducer";
import propertyPaneReducer from "./propertyPaneReducer";
import appViewReducer from "./appViewReducer";
import applicationsReducer from "./applicationsReducer";
import applicationsReducer from "@appsmith/reducers/uiReducers/applicationsReducer";
import apiPaneReducer from "./apiPaneReducer";
import datasourcePaneReducer from "./datasourcePaneReducer";
import authReducer from "./authReducer";

View File

@ -101,7 +101,7 @@ import {
import { requestModalConfirmationSaga } from "sagas/UtilSagas";
import { ModalType } from "reducers/uiReducers/modalActionReducer";
import { getFormNames, getFormValues } from "redux-form";
import { CURL_IMPORT_FORM } from "constants/forms";
import { CURL_IMPORT_FORM } from "@appsmith/constants/forms";
import { submitCurlImportForm } from "actions/importActions";
import { curlImportFormValues } from "pages/Editor/APIEditor/helpers";
import { matchBasePath } from "pages/Editor/Explorer/helpers";

View File

@ -14,7 +14,10 @@ import {
ReduxFormActionTypes,
} from "@appsmith/constants/ReduxActionConstants";
import { GetFormData, getFormData } from "selectors/formSelectors";
import { API_EDITOR_FORM_NAME, QUERY_EDITOR_FORM_NAME } from "constants/forms";
import {
API_EDITOR_FORM_NAME,
QUERY_EDITOR_FORM_NAME,
} from "@appsmith/constants/forms";
import {
DEFAULT_API_ACTION_CONFIG,
POST_BODY_FORMAT_OPTIONS_ARRAY,

View File

@ -48,7 +48,7 @@ import {
API_EDITOR_FORM_NAME,
DATASOURCE_DB_FORM,
DATASOURCE_REST_API_FORM,
} from "constants/forms";
} from "@appsmith/constants/forms";
import { validateResponse } from "./ErrorSagas";
import AnalyticsUtil from "utils/AnalyticsUtil";
import { getFormData } from "selectors/formSelectors";

View File

@ -8,7 +8,10 @@ import {
ReduxFormActionTypes,
} from "@appsmith/constants/ReduxActionConstants";
import { getFormData } from "selectors/formSelectors";
import { DATASOURCE_DB_FORM, QUERY_EDITOR_FORM_NAME } from "constants/forms";
import {
DATASOURCE_DB_FORM,
QUERY_EDITOR_FORM_NAME,
} from "@appsmith/constants/forms";
import history from "utils/history";
import { APPLICATIONS_URL, INTEGRATION_TABS } from "constants/routes";
import {

View File

@ -71,7 +71,7 @@ import {
DATASOURCE_DB_FORM,
DATASOURCE_REST_API_FORM,
QUERY_EDITOR_FORM_NAME,
} from "constants/forms";
} from "@appsmith/constants/forms";
import { Canvas } from "entities/Replay/ReplayEntity/ReplayCanvas";
import {
setAppThemingModeStackAction,

View File

@ -1,4 +1,4 @@
import { ReduxActionTypes } from "ce/constants/ReduxActionConstants";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { APP_MODE } from "entities/App";
import AppEngine from "entities/Engine";
import AppEngineFactory from "entities/Engine/factory";

View File

@ -3,7 +3,7 @@ import { AppState } from "@appsmith/reducers";
import {
ApplicationsReduxState,
creatingApplicationMap,
} from "reducers/uiReducers/applicationsReducer";
} from "@appsmith/reducers/uiReducers/applicationsReducer";
import {
ApplicationPayload,
WorkspaceDetails,

View File

@ -1,4 +1,4 @@
import { getAppsmithConfigs } from "ce/configs";
import { getAppsmithConfigs } from "@appsmith/configs";
import FormControlRegistry from "./formControl/FormControlRegistry";
import { LogLevelDesc } from "loglevel";
import localStorage from "utils/localStorage";

View File

@ -1,5 +1,8 @@
import { getAppsmithConfigs } from "@appsmith/configs";
import { createMessage, UPGRADE_TO_EE_GENERIC } from "ce/constants/messages";
import {
createMessage,
UPGRADE_TO_EE_GENERIC,
} from "@appsmith/constants/messages";
import AnalyticsUtil, { EventName } from "utils/AnalyticsUtil";
const { intercomAppID } = getAppsmithConfigs();

View File

@ -6,7 +6,7 @@ import {
FormConfigEvalObject,
DynamicValuesConfig,
} from "reducers/evaluationReducers/formEvaluationReducer";
import { ReduxActionTypes } from "ce/constants/ReduxActionConstants";
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
import { ActionConfig } from "entities/Action";
import { FormEvalActionPayload } from "sagas/FormEvaluationSaga";
import { FormConfigType } from "components/formControls/BaseControl";

View File

@ -1,7 +1,7 @@
import initSagas from "../src/sagas/InitSagas";
import apiPaneSagas from "../src/sagas/ApiPaneSagas";
import jsPaneSagas from "../src/sagas/JSPaneSagas";
import userSagas from "../src/sagas/userSagas";
import userSagas from "@appsmith/sagas/userSagas";
import pluginSagas from "../src/sagas/PluginSagas";
import workspaceSagas from "../src/sagas/WorkspaceSagas";
import importedCollectionsSagas from "../src/sagas/CollectionSagas";