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:
parent
8c4451a2fe
commit
e28e89807c
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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[] = [];
|
||||
|
|
|
|||
|
|
@ -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`;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
985
app/client/src/ce/pages/workspace/WorkspaceInviteUsersForm.tsx
Normal file
985
app/client/src/ce/pages/workspace/WorkspaceInviteUsersForm.tsx
Normal 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 haven’t 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),
|
||||
);
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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>;
|
||||
|
||||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
) {
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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[])
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
@ -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;
|
||||
1
app/client/src/ee/pages/workspace/helpers.ts
Normal file
1
app/client/src/ee/pages/workspace/helpers.ts
Normal file
|
|
@ -0,0 +1 @@
|
|||
export * from "ce/pages/workspace/helpers";
|
||||
|
|
@ -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;
|
||||
|
|
@ -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),
|
||||
]);
|
||||
}
|
||||
|
|
|
|||
52
app/client/src/ee/sagas/userSagas.tsx
Normal file
52
app/client/src/ee/sagas/userSagas.tsx
Normal 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,
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import {
|
|||
ASYNC_FUNCTION_SETTINGS_HEADING,
|
||||
createMessage,
|
||||
NO_ASYNC_FUNCTIONS,
|
||||
} from "ce/constants/messages";
|
||||
} from "@appsmith/constants/messages";
|
||||
import {
|
||||
AppIcon,
|
||||
Radio,
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 haven’t 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),
|
||||
);
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { AppState } from "@appsmith/reducers";
|
|||
import {
|
||||
ApplicationsReduxState,
|
||||
creatingApplicationMap,
|
||||
} from "reducers/uiReducers/applicationsReducer";
|
||||
} from "@appsmith/reducers/uiReducers/applicationsReducer";
|
||||
import {
|
||||
ApplicationPayload,
|
||||
WorkspaceDetails,
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user