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()
|
.first()
|
||||||
.click();
|
.click();
|
||||||
// click on selet a role
|
// click on selet a role
|
||||||
cy.wait(2000)
|
cy.wait(2000);
|
||||||
cy.xpath(HomePage.selectRole).click()
|
cy.xpath(HomePage.selectRole).click();
|
||||||
cy.get('.t--dropdown-option').should('have.length', 1).and('contain.text', `App Viewer - ${workspaceId}`)
|
cy.get(".t--dropdown-option")
|
||||||
cy.get(HomePage.closeBtn).click()
|
.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.LaunchAppFromAppHover();
|
||||||
homePage.LogOutviaAPI();
|
homePage.LogOutviaAPI();
|
||||||
|
|
@ -82,13 +83,19 @@ describe("Create new workspace and invite user & validate all roles", () => {
|
||||||
.first()
|
.first()
|
||||||
.click({ force: true });
|
.click({ force: true });
|
||||||
// cy.xpath(homePage._editPageLanding).should("exist");
|
// cy.xpath(homePage._editPageLanding).should("exist");
|
||||||
cy.wait(4000)
|
cy.wait(4000);
|
||||||
cy.xpath("//span[text()='SHARE']")
|
cy.xpath("//span[text()='SHARE']").click();
|
||||||
.click();
|
cy.wait(2000);
|
||||||
cy.wait(2000)
|
cy.xpath(HomePage.selectRole).click();
|
||||||
cy.xpath(HomePage.selectRole).click()
|
cy.get(".t--dropdown-option")
|
||||||
cy.get('.t--dropdown-option').should('have.length', 2).and('contain.text', `App Viewer - ${workspaceId}`, `Developer - ${workspaceId}`)
|
.should("have.length", 3)
|
||||||
cy.get(HomePage.closeBtn).click()
|
.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();
|
homePage.LogOutviaAPI();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -119,11 +126,21 @@ describe("Create new workspace and invite user & validate all roles", () => {
|
||||||
Cypress.env("TESTUSERNAME2"),
|
Cypress.env("TESTUSERNAME2"),
|
||||||
"App Viewer",
|
"App Viewer",
|
||||||
);
|
);
|
||||||
cy.wait(2000)
|
cy.wait(2000);
|
||||||
cy.xpath(HomePage.selectRole).click()
|
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")
|
||||||
cy.get('.t--dropdown-option').should("contain.text", `Administrator - ${workspaceId}`)
|
.should("have.length", 4)
|
||||||
cy.get(HomePage.closeBtn).click()
|
.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();
|
homePage.LogOutviaAPI();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,39 +6,44 @@ let dataSources = ObjectsRegistry.DataSources;
|
||||||
let queryName;
|
let queryName;
|
||||||
let datasourceName;
|
let datasourceName;
|
||||||
let pluginName = "Google Sheets";
|
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() {
|
describe("Google Sheets datasource row objects placeholder", function() {
|
||||||
it("Bug: 16391 - Google Sheets DS, placeholder objects keys should have quotes", function() {
|
it("Bug: 16391 - Google Sheets DS, placeholder objects keys should have quotes", function() {
|
||||||
// create new Google Sheets datasource
|
// create new Google Sheets datasource
|
||||||
dataSources.NavigateToDSCreateNew();
|
dataSources.NavigateToDSCreateNew();
|
||||||
dataSources.CreatePlugIn(pluginName);
|
dataSources.CreatePlugIn(pluginName);
|
||||||
|
|
||||||
// navigate to create query tab and create a new query
|
// navigate to create query tab and create a new query
|
||||||
cy.get("@createDatasource").then((httpResponse) => {
|
cy.get("@createDatasource").then((httpResponse) => {
|
||||||
datasourceName = httpResponse.response.body.data.name;
|
datasourceName = httpResponse.response.body.data.name;
|
||||||
// clicking on new query to write a query
|
// clicking on new query to write a query
|
||||||
cy.NavigateToQueryEditor();
|
cy.NavigateToQueryEditor();
|
||||||
cy.get(explorer.createNew).click();
|
cy.get(explorer.createNew).click();
|
||||||
cy.get("div:contains('" + datasourceName + " Query')").last().click();
|
cy.get("div:contains('" + datasourceName + " Query')")
|
||||||
|
.last()
|
||||||
|
.click();
|
||||||
|
|
||||||
// fill the create new api google sheets form
|
// fill the create new api google sheets form
|
||||||
// and check for rowobject placeholder text
|
// and check for rowobject placeholder text
|
||||||
cy.get(datasource.gSheetsOperationDropdown).click();
|
cy.get(datasource.gSheetsOperationDropdown).click();
|
||||||
cy.get(datasource.gSheetsInsertOneOption).click();
|
cy.get(datasource.gSheetsInsertOneOption).click();
|
||||||
|
|
||||||
cy.get(datasource.gSheetsEntityDropdown).click();
|
cy.get(datasource.gSheetsEntityDropdown).click();
|
||||||
cy.get(datasource.gSheetsSheetRowsOption).click();
|
cy.get(datasource.gSheetsSheetRowsOption).click();
|
||||||
|
|
||||||
cy.get(datasource.gSheetsCodeMirrorPlaceholder).should('have.text', placeholderText);
|
cy.get(datasource.gSheetsCodeMirrorPlaceholder).should(
|
||||||
|
"have.text",
|
||||||
|
placeholderText,
|
||||||
|
);
|
||||||
|
|
||||||
// delete query and datasource after test is done
|
// delete query and datasource after test is done
|
||||||
cy.get("@createNewApi").then((httpResponse) => {
|
cy.get("@createNewApi").then((httpResponse) => {
|
||||||
queryName = httpResponse.response.body.data.name;
|
queryName = httpResponse.response.body.data.name;
|
||||||
cy.deleteQueryUsingContext();
|
cy.deleteQueryUsingContext();
|
||||||
cy.deleteDatasource(datasourceName);
|
cy.deleteDatasource(datasourceName);
|
||||||
})
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
});
|
||||||
);
|
});
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,15 @@ export class HomePage {
|
||||||
".t--workspace-section:contains(" +
|
".t--workspace-section:contains(" +
|
||||||
workspaceName +
|
workspaceName +
|
||||||
") button:contains('Share')";
|
") 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 + "']";
|
_visibleTextSpan = (spanText: string) => "//span[text()='" + spanText + "']";
|
||||||
private _userRole = (role: string, workspaceName: string) =>
|
private _userRole = (role: string, workspaceName: string) =>
|
||||||
"//div[contains(@class, 'label-container')]//span[1][text()='" +
|
"//div[contains(@class, 'label-container')]//span[1][text()='" +
|
||||||
role + ' - ' + workspaceName + "']";
|
role +
|
||||||
|
" - " +
|
||||||
|
workspaceName +
|
||||||
|
"']";
|
||||||
|
|
||||||
private _manageUsers = ".manageUsers";
|
private _manageUsers = ".manageUsers";
|
||||||
private _appHome = "//a[@href='/applications']";
|
private _appHome = "//a[@href='/applications']";
|
||||||
|
|
@ -50,8 +54,8 @@ export class HomePage {
|
||||||
"//td[text()='" +
|
"//td[text()='" +
|
||||||
email +
|
email +
|
||||||
"']/following-sibling::td//span[contains(@class, 't--deleteUser')]";
|
"']/following-sibling::td//span[contains(@class, 't--deleteUser')]";
|
||||||
private _userRoleDropDown = (role: string, WorkspaceName:string)=> "//span[text()='" +
|
private _userRoleDropDown = (role: string, WorkspaceName: string) =>
|
||||||
role + " - "+ WorkspaceName + "']";
|
"//span[text()='" + role + " - " + WorkspaceName + "']";
|
||||||
//private _userRoleDropDown = (email: string) => "//td[text()='" + email + "']/following-sibling::td"
|
//private _userRoleDropDown = (email: string) => "//td[text()='" + email + "']/following-sibling::td"
|
||||||
private _leaveWorkspaceConfirmModal = ".t--member-delete-confirmation-modal";
|
private _leaveWorkspaceConfirmModal = ".t--member-delete-confirmation-modal";
|
||||||
private _workspaceImportAppModal = ".t--import-application-modal";
|
private _workspaceImportAppModal = ".t--import-application-modal";
|
||||||
|
|
@ -160,8 +164,9 @@ export class HomePage {
|
||||||
cy.get(this._homeIcon).click({ force: true });
|
cy.get(this._homeIcon).click({ force: true });
|
||||||
this.agHelper.Sleep(2000);
|
this.agHelper.Sleep(2000);
|
||||||
//cy.wait("@applications"); this randomly fails & introduces flakyness hence commenting!
|
//cy.wait("@applications"); this randomly fails & introduces flakyness hence commenting!
|
||||||
this.agHelper.AssertElementVisible(this._homePageAppCreateBtn).then($ele=>
|
this.agHelper
|
||||||
expect($ele).be.enabled);
|
.AssertElementVisible(this._homePageAppCreateBtn)
|
||||||
|
.then(($ele) => expect($ele).be.enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CreateNewApplication() {
|
public CreateNewApplication() {
|
||||||
|
|
@ -181,7 +186,7 @@ export class HomePage {
|
||||||
this.agHelper.ValidateNetworkStatus("@createNewApplication", 201);
|
this.agHelper.ValidateNetworkStatus("@createNewApplication", 201);
|
||||||
cy.get(this.locator._loading).should("not.exist");
|
cy.get(this.locator._loading).should("not.exist");
|
||||||
this.agHelper.Sleep(2000);
|
this.agHelper.Sleep(2000);
|
||||||
if(appname) this.RenameApplication(appname);
|
if (appname) this.RenameApplication(appname);
|
||||||
cy.get(this._buildFromScratchActionCard).click();
|
cy.get(this._buildFromScratchActionCard).click();
|
||||||
//this.agHelper.ValidateNetworkStatus("@updateApplication", 200);
|
//this.agHelper.ValidateNetworkStatus("@updateApplication", 200);
|
||||||
}
|
}
|
||||||
|
|
@ -310,7 +315,7 @@ export class HomePage {
|
||||||
cy.log(workspaceName, email, currentRole);
|
cy.log(workspaceName, email, currentRole);
|
||||||
cy.xpath(this._userRoleDropDown(currentRole, workspaceName))
|
cy.xpath(this._userRoleDropDown(currentRole, workspaceName))
|
||||||
.first()
|
.first()
|
||||||
.click({force:true})
|
.click({ force: true });
|
||||||
|
|
||||||
//cy.xpath(this._userRoleDropDown(email)).first().click({force: true});
|
//cy.xpath(this._userRoleDropDown(email)).first().click({force: true});
|
||||||
cy.xpath(this._visibleTextSpan(`${newRole} - ${workspaceName}`))
|
cy.xpath(this._visibleTextSpan(`${newRole} - ${workspaceName}`))
|
||||||
|
|
@ -353,7 +358,6 @@ export class HomePage {
|
||||||
cy.contains(successMessage);
|
cy.contains(successMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public DeleteWorkspace(workspaceNameToDelete: string) {
|
public DeleteWorkspace(workspaceNameToDelete: string) {
|
||||||
cy.get(this._homeIcon).click();
|
cy.get(this._homeIcon).click();
|
||||||
this.agHelper.GetNClick(
|
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_ROLE_SELECT_LABEL = () => `Role`;
|
||||||
export const INVITE_USERS_EMAIL_LIST_LABEL = () => `User emails`;
|
export const INVITE_USERS_EMAIL_LIST_LABEL = () => `User emails`;
|
||||||
export const INVITE_USERS_ADD_EMAIL_LIST_FIELD = () => `Add more`;
|
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_BUTTON_TEXT = () => `Invite users`;
|
||||||
export const INVITE_USERS_SUBMIT_SUCCESS = () =>
|
export const INVITE_USERS_SUBMIT_SUCCESS = () =>
|
||||||
`The users have been invited successfully`;
|
`The users have been invited successfully`;
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export interface Setting {
|
||||||
isVisible?: (values: Record<string, any>) => boolean;
|
isVisible?: (values: Record<string, any>) => boolean;
|
||||||
isHidden?: boolean;
|
isHidden?: boolean;
|
||||||
isDisabled?: (values: Record<string, any>) => boolean;
|
isDisabled?: (values: Record<string, any>) => boolean;
|
||||||
calloutType?: "Info" | "Warning";
|
calloutType?: "Info" | "Warning" | "Notify";
|
||||||
advanced?: Setting[];
|
advanced?: Setting[];
|
||||||
isRequired?: boolean;
|
isRequired?: boolean;
|
||||||
formName?: string;
|
formName?: string;
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
LOGIN_FORM_NAME,
|
LOGIN_FORM_NAME,
|
||||||
LOGIN_FORM_EMAIL_FIELD_NAME,
|
LOGIN_FORM_EMAIL_FIELD_NAME,
|
||||||
LOGIN_FORM_PASSWORD_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 { FORGOT_PASSWORD_URL, SETUP, SIGN_UP_URL } from "constants/routes";
|
||||||
import {
|
import {
|
||||||
LOGIN_PAGE_TITLE,
|
LOGIN_PAGE_TITLE,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { reduxForm, InjectedFormProps, formValueSelector } from "redux-form";
|
import { reduxForm, InjectedFormProps, formValueSelector } from "redux-form";
|
||||||
import { AUTH_LOGIN_URL } from "constants/routes";
|
import { AUTH_LOGIN_URL } from "constants/routes";
|
||||||
import { SIGNUP_FORM_NAME } from "constants/forms";
|
import { SIGNUP_FORM_NAME } from "@appsmith/constants/forms";
|
||||||
import {
|
import {
|
||||||
RouteComponentProps,
|
RouteComponentProps,
|
||||||
useHistory,
|
useHistory,
|
||||||
|
|
@ -48,7 +48,7 @@ import PerformanceTracker, {
|
||||||
PerformanceTransactionName,
|
PerformanceTransactionName,
|
||||||
} from "utils/PerformanceTracker";
|
} 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 { getAppsmithConfigs } from "@appsmith/configs";
|
||||||
import { useScript, ScriptStatus, AddScriptTo } from "utils/hooks/useScript";
|
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 { DatasourceDataState } from "reducers/entityReducers/datasourceReducer";
|
||||||
import { AppViewReduxState } from "reducers/uiReducers/appViewReducer";
|
import { AppViewReduxState } from "reducers/uiReducers/appViewReducer";
|
||||||
import { DatasourcePaneReduxState } from "reducers/uiReducers/datasourcePaneReducer";
|
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 { PageListReduxState } from "reducers/entityReducers/pageListReducer";
|
||||||
import { ApiPaneReduxState } from "reducers/uiReducers/apiPaneReducer";
|
import { ApiPaneReduxState } from "reducers/uiReducers/apiPaneReducer";
|
||||||
import { QueryPaneReduxState } from "reducers/uiReducers/queryPaneReducer";
|
import { QueryPaneReduxState } from "reducers/uiReducers/queryPaneReducer";
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import { CreateApplicationFormValues } from "pages/Applications/helpers";
|
||||||
import { AppLayoutConfig } from "reducers/entityReducers/pageListReducer";
|
import { AppLayoutConfig } from "reducers/entityReducers/pageListReducer";
|
||||||
import { ConnectToGitResponse } from "actions/gitSyncActions";
|
import { ConnectToGitResponse } from "actions/gitSyncActions";
|
||||||
|
|
||||||
const initialState: ApplicationsReduxState = {
|
export const initialState: ApplicationsReduxState = {
|
||||||
isFetchingApplications: false,
|
isFetchingApplications: false,
|
||||||
isSavingAppName: false,
|
isSavingAppName: false,
|
||||||
isErrorSavingAppName: false,
|
isErrorSavingAppName: false,
|
||||||
|
|
@ -35,7 +35,7 @@ const initialState: ApplicationsReduxState = {
|
||||||
workspaceIdForImport: null,
|
workspaceIdForImport: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const applicationsReducer = createReducer(initialState, {
|
export const handlers = {
|
||||||
[ReduxActionTypes.DELETE_APPLICATION_INIT]: (
|
[ReduxActionTypes.DELETE_APPLICATION_INIT]: (
|
||||||
state: ApplicationsReduxState,
|
state: ApplicationsReduxState,
|
||||||
) => {
|
) => {
|
||||||
|
|
@ -487,7 +487,9 @@ const applicationsReducer = createReducer(initialState, {
|
||||||
applicationList: [...state.applicationList, action.payload],
|
applicationList: [...state.applicationList, action.payload],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
};
|
||||||
|
|
||||||
|
const applicationsReducer = createReducer(initialState, handlers);
|
||||||
|
|
||||||
export type creatingApplicationMap = Record<string, boolean>;
|
export type creatingApplicationMap = Record<string, boolean>;
|
||||||
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
} from "@appsmith/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { APPLICATIONS_URL } from "constants/routes";
|
import { APPLICATIONS_URL } from "constants/routes";
|
||||||
import { User } from "constants/userConstants";
|
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 history from "utils/history";
|
||||||
import { validateResponse } from "sagas/ErrorSagas";
|
import { validateResponse } from "sagas/ErrorSagas";
|
||||||
import { getAppsmithConfigs } from "@appsmith/configs";
|
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||||
|
|
@ -103,7 +103,7 @@ export function* RestartServerPoll() {
|
||||||
yield call(RestryRestartServerPoll);
|
yield call(RestryRestartServerPoll);
|
||||||
}
|
}
|
||||||
|
|
||||||
function* RestryRestartServerPoll() {
|
export function* RestryRestartServerPoll() {
|
||||||
let pollCount = 0;
|
let pollCount = 0;
|
||||||
const maxPollCount = RESTART_POLL_TIMEOUT / RESTART_POLL_INTERVAL;
|
const maxPollCount = RESTART_POLL_TIMEOUT / RESTART_POLL_INTERVAL;
|
||||||
while (pollCount < maxPollCount) {
|
while (pollCount < maxPollCount) {
|
||||||
|
|
@ -156,30 +156,3 @@ export function* SendTestEmail(action: ReduxAction<SendTestEmailPayload>) {
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} 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 initSagas from "sagas/InitSagas";
|
||||||
import apiPaneSagas from "sagas/ApiPaneSagas";
|
import apiPaneSagas from "sagas/ApiPaneSagas";
|
||||||
import jsPaneSagas from "sagas/JSPaneSagas";
|
import jsPaneSagas from "sagas/JSPaneSagas";
|
||||||
import userSagas from "sagas/userSagas";
|
import userSagas from "@appsmith/sagas/userSagas";
|
||||||
import pluginSagas from "sagas/PluginSagas";
|
import pluginSagas from "sagas/PluginSagas";
|
||||||
import workspaceSagas from "sagas/WorkspaceSagas";
|
import workspaceSagas from "sagas/WorkspaceSagas";
|
||||||
import importedCollectionsSagas from "sagas/CollectionSagas";
|
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 {
|
import {
|
||||||
ReduxAction,
|
ReduxAction,
|
||||||
ReduxActionWithPromise,
|
ReduxActionWithPromise,
|
||||||
|
|
@ -22,7 +22,7 @@ import {
|
||||||
validateResponse,
|
validateResponse,
|
||||||
getResponseErrorMessage,
|
getResponseErrorMessage,
|
||||||
callAPI,
|
callAPI,
|
||||||
} from "./ErrorSagas";
|
} from "sagas/ErrorSagas";
|
||||||
import {
|
import {
|
||||||
logoutUserSuccess,
|
logoutUserSuccess,
|
||||||
logoutUserError,
|
logoutUserError,
|
||||||
|
|
@ -34,7 +34,7 @@ import {
|
||||||
fetchFeatureFlagsError,
|
fetchFeatureFlagsError,
|
||||||
} from "actions/userActions";
|
} from "actions/userActions";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
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, {
|
import PerformanceTracker, {
|
||||||
PerformanceTransactionName,
|
PerformanceTransactionName,
|
||||||
} from "utils/PerformanceTracker";
|
} 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 {
|
try {
|
||||||
const response: ApiResponse = yield call(UserApi.deletePhoto);
|
const response: ApiResponse = yield call(UserApi.deletePhoto);
|
||||||
//@ts-expect-error: response is of type unknown
|
//@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 }>,
|
action: ReduxAction<{ file: File; callback: (id: string) => void }>,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -432,7 +434,7 @@ function* updatePhoto(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* fetchFeatureFlags() {
|
export function* fetchFeatureFlags() {
|
||||||
try {
|
try {
|
||||||
const response: ApiResponse = yield call(UserApi.fetchFeatureFlags);
|
const response: ApiResponse = yield call(UserApi.fetchFeatureFlags);
|
||||||
const isValidResponse: boolean = yield validateResponse(response);
|
const isValidResponse: boolean = yield validateResponse(response);
|
||||||
|
|
@ -446,7 +448,7 @@ function* fetchFeatureFlags() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function* updateFirstTimeUserOnboardingSage() {
|
export function* updateFirstTimeUserOnboardingSage() {
|
||||||
const enable: string | null = yield getEnableFirstTimeUserOnboarding();
|
const enable: string | null = yield getEnableFirstTimeUserOnboarding();
|
||||||
|
|
||||||
if (enable) {
|
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(
|
export function* leaveWorkspaceSaga(
|
||||||
action: ReduxAction<LeaveWorkspaceRequest>,
|
action: ReduxAction<LeaveWorkspaceRequest>,
|
||||||
) {
|
) {
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { render, screen } from "test/testUtils";
|
import { render, screen } from "test/testUtils";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { CopyUrlReduxForm } from "./CopyUrlForm";
|
import { CopyUrlReduxForm } from "./CopyUrlForm";
|
||||||
import { REDIRECT_URL_FORM } from "constants/forms";
|
import { REDIRECT_URL_FORM } from "@appsmith/constants/forms";
|
||||||
|
|
||||||
let container: any = null;
|
let container: any = null;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { render } from "test/testUtils";
|
import { render } from "test/testUtils";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import UneditableField from "./UneditableField";
|
import UneditableField from "./UneditableField";
|
||||||
import { REDIRECT_URL_FORM } from "constants/forms";
|
import { REDIRECT_URL_FORM } from "@appsmith/constants/forms";
|
||||||
import { reduxForm } from "redux-form";
|
import { reduxForm } from "redux-form";
|
||||||
|
|
||||||
let container: any = null;
|
let container: any = null;
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,33 @@ import { isPermitted } from "pages/Applications/permissionHelpers";
|
||||||
import Dialog from "components/ads/DialogComponent";
|
import Dialog from "components/ads/DialogComponent";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { setShowAppInviteUsersDialog } from "actions/applicationActions";
|
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 = {
|
type FormDialogComponentProps = {
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
canOutsideClickClose?: boolean;
|
canOutsideClickClose?: boolean;
|
||||||
workspaceId?: string;
|
workspaceId?: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
message?: string;
|
||||||
Form: any;
|
Form: any;
|
||||||
trigger: ReactNode;
|
trigger: ReactNode;
|
||||||
onClose?: () => void;
|
onClose?: () => void;
|
||||||
|
|
@ -24,28 +44,67 @@ type FormDialogComponentProps = {
|
||||||
hoverColor?: string;
|
hoverColor?: string;
|
||||||
bgColor?: 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) {
|
export function FormDialogComponent(props: FormDialogComponentProps) {
|
||||||
const [isOpen, setIsOpenState] = useState(!!props.isOpen);
|
const [isOpen, setIsOpenState] = useState(!!props.isOpen);
|
||||||
|
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setIsOpen(!!props.isOpen);
|
||||||
|
}, [props.isOpen]);
|
||||||
|
|
||||||
const setIsOpen = (isOpen: boolean) => {
|
const setIsOpen = (isOpen: boolean) => {
|
||||||
setIsOpenState(isOpen);
|
setIsOpenState(isOpen);
|
||||||
dispatch(setShowAppInviteUsersDialog(isOpen));
|
dispatch(setShowAppInviteUsersDialog(isOpen));
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setIsOpen(!!props.isOpen);
|
|
||||||
}, [props.isOpen]);
|
|
||||||
|
|
||||||
const Form = props.Form;
|
|
||||||
|
|
||||||
const onCloseHandler = () => {
|
const onCloseHandler = () => {
|
||||||
props?.onClose?.();
|
props?.onClose?.();
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const updatedTabs: TabProp[] =
|
||||||
|
props.tabs && props.tabs.length > 0
|
||||||
|
? getTabs(props.tabs, setIsOpen, props.applicationId, props.workspaceId)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const Form = props.Form;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
props.permissions &&
|
props.permissions &&
|
||||||
props.permissionRequired &&
|
props.permissionRequired &&
|
||||||
|
|
@ -65,12 +124,27 @@ export function FormDialogComponent(props: FormDialogComponentProps) {
|
||||||
title={props.title}
|
title={props.title}
|
||||||
trigger={props.trigger}
|
trigger={props.trigger}
|
||||||
>
|
>
|
||||||
<Form
|
{updatedTabs && updatedTabs.length > 0 ? (
|
||||||
{...props.customProps}
|
<TabWrapper>
|
||||||
applicationId={props.applicationId}
|
<LabelText type={TextType.P0}>{props.message}</LabelText>
|
||||||
onCancel={() => setIsOpen(false)}
|
<TabComponent
|
||||||
workspaceId={props.workspaceId}
|
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>
|
</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 React, { useEffect, useState } from "react";
|
||||||
import { DropdownOnSelect } from "./SelectField";
|
import { DropdownOnSelect } from "./SelectField";
|
||||||
|
|
||||||
|
|
@ -21,6 +21,7 @@ type DropdownWrapperProps = {
|
||||||
labelRenderer?: (selected: Partial<DropdownOption>[]) => JSX.Element;
|
labelRenderer?: (selected: Partial<DropdownOption>[]) => JSX.Element;
|
||||||
fillOptions?: boolean;
|
fillOptions?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
renderOption?: RenderOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
function DropdownWrapper(props: DropdownWrapperProps) {
|
function DropdownWrapper(props: DropdownWrapperProps) {
|
||||||
|
|
@ -71,6 +72,7 @@ function DropdownWrapper(props: DropdownWrapperProps) {
|
||||||
options={props.options}
|
options={props.options}
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
removeSelectedOption={onRemoveOptions}
|
removeSelectedOption={onRemoveOptions}
|
||||||
|
renderOption={props?.renderOption}
|
||||||
selected={
|
selected={
|
||||||
props.isMultiSelect
|
props.isMultiSelect
|
||||||
? (props.selected as DropdownOption[])
|
? (props.selected as DropdownOption[])
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import CodeEditor, {
|
||||||
EditorProps,
|
EditorProps,
|
||||||
} from "components/editorComponents/CodeEditor";
|
} from "components/editorComponents/CodeEditor";
|
||||||
import { CodeEditorBorder } from "components/editorComponents/CodeEditor/EditorConfig";
|
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 { AppState } from "@appsmith/reducers";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import get from "lodash/get";
|
import get from "lodash/get";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
WrappedFieldMetaProps,
|
WrappedFieldMetaProps,
|
||||||
WrappedFieldInputProps,
|
WrappedFieldInputProps,
|
||||||
} from "redux-form";
|
} from "redux-form";
|
||||||
import { DropdownOption } from "design-system";
|
import { DropdownOption, RenderOption } from "design-system";
|
||||||
import DropdownWrapper from "./DropdownWrapper";
|
import DropdownWrapper from "./DropdownWrapper";
|
||||||
|
|
||||||
const renderComponent = (
|
const renderComponent = (
|
||||||
|
|
@ -33,6 +33,7 @@ type SelectFieldProps = {
|
||||||
labelRenderer?: (selected: Partial<DropdownOption>[]) => JSX.Element;
|
labelRenderer?: (selected: Partial<DropdownOption>[]) => JSX.Element;
|
||||||
fillOptions?: boolean;
|
fillOptions?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
renderOption?: RenderOption;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function SelectField(props: SelectFieldProps) {
|
export function SelectField(props: SelectFieldProps) {
|
||||||
|
|
@ -50,6 +51,7 @@ export function SelectField(props: SelectFieldProps) {
|
||||||
outline={props.outline}
|
outline={props.outline}
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
removeSelectedOption={props.removeSelectedOption}
|
removeSelectedOption={props.removeSelectedOption}
|
||||||
|
renderOption={props?.renderOption}
|
||||||
selected={props.selected}
|
selected={props.selected}
|
||||||
showLabelOnly={props.showLabelOnly}
|
showLabelOnly={props.showLabelOnly}
|
||||||
size={props.size}
|
size={props.size}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React from "react";
|
import React, { ReactElement } from "react";
|
||||||
import {
|
import {
|
||||||
Field,
|
Field,
|
||||||
WrappedFieldMetaProps,
|
WrappedFieldMetaProps,
|
||||||
|
|
@ -23,7 +23,9 @@ type TagListFieldProps = {
|
||||||
type: string;
|
type: string;
|
||||||
label: string;
|
label: string;
|
||||||
intent: Intent;
|
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) {
|
function TagListField(props: TagListFieldProps) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { ControlType } from "constants/PropertyControlConstants";
|
||||||
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
|
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
|
||||||
import { AppState } from "@appsmith/reducers";
|
import { AppState } from "@appsmith/reducers";
|
||||||
import { formValueSelector } from "redux-form";
|
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 { connect } from "react-redux";
|
||||||
import { actionPathFromName } from "components/formControls/utils";
|
import { actionPathFromName } from "components/formControls/utils";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import {
|
||||||
EditorModes,
|
EditorModes,
|
||||||
TabBehaviour,
|
TabBehaviour,
|
||||||
} from "components/editorComponents/CodeEditor/EditorConfig";
|
} 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 { AppState } from "@appsmith/reducers";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import TemplateMenu from "pages/Editor/QueryEditor/TemplateMenu";
|
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,
|
FetchAdminSettingsErrorSaga,
|
||||||
SaveAdminSettingsSaga,
|
SaveAdminSettingsSaga,
|
||||||
RestartServerPoll,
|
RestartServerPoll,
|
||||||
|
RestryRestartServerPoll,
|
||||||
SendTestEmail,
|
SendTestEmail,
|
||||||
} from "ce/sagas/SuperUserSagas";
|
} from "ce/sagas/SuperUserSagas";
|
||||||
import {
|
import {
|
||||||
|
|
@ -24,6 +25,10 @@ export function* InitSuperUserSaga(action: ReduxAction<User>) {
|
||||||
),
|
),
|
||||||
takeLatest(ReduxActionTypes.SAVE_ADMIN_SETTINGS, SaveAdminSettingsSaga),
|
takeLatest(ReduxActionTypes.SAVE_ADMIN_SETTINGS, SaveAdminSettingsSaga),
|
||||||
takeLatest(ReduxActionTypes.RESTART_SERVER_POLL, RestartServerPoll),
|
takeLatest(ReduxActionTypes.RESTART_SERVER_POLL, RestartServerPoll),
|
||||||
|
takeLatest(
|
||||||
|
ReduxActionTypes.RETRY_RESTART_SERVER_POLL,
|
||||||
|
RestryRestartServerPoll,
|
||||||
|
),
|
||||||
takeLatest(ReduxActionTypes.SEND_TEST_EMAIL, SendTestEmail),
|
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,
|
ApplicationPayload,
|
||||||
ReduxActionErrorTypes,
|
ReduxActionErrorTypes,
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
} from "ce/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { addBranchParam } from "constants/routes";
|
import { addBranchParam } from "constants/routes";
|
||||||
import { APP_MODE } from "entities/App";
|
import { APP_MODE } from "entities/App";
|
||||||
import { all, call, put, select } from "redux-saga/effects";
|
import { all, call, put, select } from "redux-saga/effects";
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import {
|
import {
|
||||||
ReduxActionErrorTypes,
|
ReduxActionErrorTypes,
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
} from "ce/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { APP_MODE } from "entities/App";
|
import { APP_MODE } from "entities/App";
|
||||||
import { call, put } from "redux-saga/effects";
|
import { call, put } from "redux-saga/effects";
|
||||||
import { failFastApiCalls } from "sagas/InitSagas";
|
import { failFastApiCalls } from "sagas/InitSagas";
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
ApplicationPayload,
|
ApplicationPayload,
|
||||||
ReduxActionErrorTypes,
|
ReduxActionErrorTypes,
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
} from "ce/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { getPersistentAppStore } from "constants/AppConstants";
|
import { getPersistentAppStore } from "constants/AppConstants";
|
||||||
import { APP_MODE } from "entities/App";
|
import { APP_MODE } from "entities/App";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ApplicationVersion } from "actions/applicationActions";
|
import { ApplicationVersion } from "actions/applicationActions";
|
||||||
import { ApplicationPayload } from "ce/constants/ReduxActionConstants";
|
import { ApplicationPayload } from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { APP_MODE } from "entities/App";
|
import { APP_MODE } from "entities/App";
|
||||||
import { select } from "redux-saga/effects";
|
import { select } from "redux-saga/effects";
|
||||||
import { builderURL } from "RouteBuilder";
|
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 { APP_MODE } from "entities/App";
|
||||||
import { select } from "redux-saga/effects";
|
import { select } from "redux-saga/effects";
|
||||||
import { fillPathname, viewerURL } from "RouteBuilder";
|
import { fillPathname, viewerURL } from "RouteBuilder";
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,12 @@ import BackToHomeButton from "./BackToHomeButton";
|
||||||
import TourCompletionMessage from "pages/Editor/GuidedTour/TourCompletionMessage";
|
import TourCompletionMessage from "pages/Editor/GuidedTour/TourCompletionMessage";
|
||||||
import { useHref } from "pages/Editor/utils";
|
import { useHref } from "pages/Editor/utils";
|
||||||
import { builderURL } from "RouteBuilder";
|
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",
|
bgColor: "transparent",
|
||||||
}}
|
}}
|
||||||
isOpen={showAppInviteUsersDialog}
|
isOpen={showAppInviteUsersDialog}
|
||||||
|
links={inviteModalLinks}
|
||||||
|
message={createMessage(INVITE_USERS_MESSAGE)}
|
||||||
|
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
|
||||||
title={currentApplicationDetails.name}
|
title={currentApplicationDetails.name}
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,12 @@ import { useHref } from "pages/Editor/utils";
|
||||||
import { APP_MODE } from "entities/App";
|
import { APP_MODE } from "entities/App";
|
||||||
import { builderURL, viewerURL } from "RouteBuilder";
|
import { builderURL, viewerURL } from "RouteBuilder";
|
||||||
import { trimQueryString } from "utils/helpers";
|
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 = {
|
type AppViewerHeaderProps = {
|
||||||
isOpen?: boolean;
|
isOpen?: boolean;
|
||||||
|
|
@ -112,6 +118,9 @@ export function PageMenu(props: AppViewerHeaderProps) {
|
||||||
bgColor: "transparent",
|
bgColor: "transparent",
|
||||||
}}
|
}}
|
||||||
isOpen={showAppInviteUsersDialog}
|
isOpen={showAppInviteUsersDialog}
|
||||||
|
links={inviteModalLinks}
|
||||||
|
message={createMessage(INVITE_USERS_MESSAGE)}
|
||||||
|
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
|
||||||
title={application.name}
|
title={application.name}
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Form, reduxForm, InjectedFormProps, Field } from "redux-form";
|
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 {
|
import {
|
||||||
createMessage,
|
createMessage,
|
||||||
ERROR_MESSAGE_NAME_EMPTY,
|
ERROR_MESSAGE_NAME_EMPTY,
|
||||||
|
|
|
||||||
|
|
@ -35,13 +35,16 @@ import {
|
||||||
import PageWrapper from "pages/common/PageWrapper";
|
import PageWrapper from "pages/common/PageWrapper";
|
||||||
import SubHeader from "pages/common/SubHeader";
|
import SubHeader from "pages/common/SubHeader";
|
||||||
import ApplicationCard from "./ApplicationCard";
|
import ApplicationCard from "./ApplicationCard";
|
||||||
import WorkspaceInviteUsersForm from "pages/workspace/WorkspaceInviteUsersForm";
|
import WorkspaceInviteUsersForm from "@appsmith/pages/workspace/WorkspaceInviteUsersForm";
|
||||||
import { isPermitted, PERMISSION_TYPE } from "./permissionHelpers";
|
import { isPermitted, PERMISSION_TYPE } from "./permissionHelpers";
|
||||||
import FormDialogComponent from "components/editorComponents/form/FormDialogComponent";
|
import FormDialogComponent from "components/editorComponents/form/FormDialogComponent";
|
||||||
import Dialog from "components/ads/DialogComponent";
|
import Dialog from "components/ads/DialogComponent";
|
||||||
import { User } from "constants/userConstants";
|
import { User } from "constants/userConstants";
|
||||||
import { getCurrentUser, selectFeatureFlags } from "selectors/usersSelectors";
|
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 {
|
import {
|
||||||
DropdownOnSelectActions,
|
DropdownOnSelectActions,
|
||||||
getOnSelectAction,
|
getOnSelectAction,
|
||||||
|
|
@ -70,7 +73,7 @@ import PerformanceTracker, {
|
||||||
PerformanceTransactionName,
|
PerformanceTransactionName,
|
||||||
} from "utils/PerformanceTracker";
|
} from "utils/PerformanceTracker";
|
||||||
import { loadingUserWorkspaces } from "./ApplicationLoaders";
|
import { loadingUserWorkspaces } from "./ApplicationLoaders";
|
||||||
import { creatingApplicationMap } from "reducers/uiReducers/applicationsReducer";
|
import { creatingApplicationMap } from "@appsmith/reducers/uiReducers/applicationsReducer";
|
||||||
import EditableText, {
|
import EditableText, {
|
||||||
EditInteractionKind,
|
EditInteractionKind,
|
||||||
SavingState,
|
SavingState,
|
||||||
|
|
@ -81,13 +84,15 @@ import { leaveWorkspace } from "actions/userActions";
|
||||||
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
import CenteredWrapper from "components/designSystems/appsmith/CenteredWrapper";
|
||||||
import NoSearchImage from "assets/images/NoSearchResult.svg";
|
import NoSearchImage from "assets/images/NoSearchResult.svg";
|
||||||
import { getNextEntityName, getRandomPaletteColor } from "utils/AppsmithUtils";
|
import { getNextEntityName, getRandomPaletteColor } from "utils/AppsmithUtils";
|
||||||
import { createWorkspaceSubmitHandler } from "pages/workspace/helpers";
|
import { createWorkspaceSubmitHandler } from "@appsmith/pages/workspace/helpers";
|
||||||
import ImportApplicationModal from "./ImportApplicationModal";
|
import ImportApplicationModal from "./ImportApplicationModal";
|
||||||
import {
|
import {
|
||||||
createMessage,
|
createMessage,
|
||||||
NO_APPS_FOUND,
|
NO_APPS_FOUND,
|
||||||
WORKSPACES_HEADING,
|
WORKSPACES_HEADING,
|
||||||
SEARCH_APPS,
|
SEARCH_APPS,
|
||||||
|
INVITE_USERS_MESSAGE,
|
||||||
|
INVITE_USERS_PLACEHOLDER,
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
import { ReactComponent as NoAppsFoundIcon } from "assets/svg/no-apps-icon.svg";
|
import { ReactComponent as NoAppsFoundIcon } from "assets/svg/no-apps-icon.svg";
|
||||||
|
|
||||||
|
|
@ -702,7 +707,11 @@ function ApplicationsSection(props: any) {
|
||||||
onClose={() => setSelectedWorkspaceId("")}
|
onClose={() => setSelectedWorkspaceId("")}
|
||||||
title={`Invite Users to ${workspace.name}`}
|
title={`Invite Users to ${workspace.name}`}
|
||||||
>
|
>
|
||||||
<Form workspaceId={workspace.id} />
|
<Form
|
||||||
|
links={inviteModalLinks}
|
||||||
|
message={createMessage(INVITE_USERS_MESSAGE)}
|
||||||
|
workspaceId={workspace.id}
|
||||||
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
)}
|
)}
|
||||||
{selectedWorkspaceIdForImportApplication && (
|
{selectedWorkspaceIdForImportApplication && (
|
||||||
|
|
@ -725,6 +734,9 @@ function ApplicationsSection(props: any) {
|
||||||
<FormDialogComponent
|
<FormDialogComponent
|
||||||
Form={WorkspaceInviteUsersForm}
|
Form={WorkspaceInviteUsersForm}
|
||||||
canOutsideClickClose
|
canOutsideClickClose
|
||||||
|
links={inviteModalLinks}
|
||||||
|
message={createMessage(INVITE_USERS_MESSAGE)}
|
||||||
|
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
|
||||||
title={`Invite Users to ${workspace.name}`}
|
title={`Invite Users to ${workspace.name}`}
|
||||||
trigger={
|
trigger={
|
||||||
<Button
|
<Button
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
import history from "utils/history";
|
import history from "utils/history";
|
||||||
import { getQueryParams } from "utils/URLUtils";
|
import { getQueryParams } from "utils/URLUtils";
|
||||||
import { AuthType } from "entities/Datasource/RestAPIForm";
|
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 { formValueSelector } from "redux-form";
|
||||||
import { AppState } from "@appsmith/reducers";
|
import { AppState } from "@appsmith/reducers";
|
||||||
import { ReactComponent as SheildSuccess } from "assets/icons/ads/shield-success.svg";
|
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 styled from "styled-components";
|
||||||
import { AppState } from "@appsmith/reducers";
|
import { AppState } from "@appsmith/reducers";
|
||||||
import { ActionDataState } from "reducers/entityReducers/actionsReducer";
|
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 { BuilderRouteParams } from "constants/routes";
|
||||||
import { curlImportFormValues, curlImportSubmitHandler } from "./helpers";
|
import { curlImportFormValues, curlImportSubmitHandler } from "./helpers";
|
||||||
import { createNewApiName } from "utils/AppsmithUtils";
|
import { createNewApiName } from "utils/AppsmithUtils";
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import styled from "styled-components";
|
||||||
import FormLabel from "components/editorComponents/FormLabel";
|
import FormLabel from "components/editorComponents/FormLabel";
|
||||||
import FormRow from "components/editorComponents/FormRow";
|
import FormRow from "components/editorComponents/FormRow";
|
||||||
import { PaginationField, SuggestedWidget } from "api/ActionAPI";
|
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 Pagination from "./Pagination";
|
||||||
import { Action, PaginationType } from "entities/Action";
|
import { Action, PaginationType } from "entities/Action";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import {
|
||||||
POST_BODY_FORMAT_OPTIONS,
|
POST_BODY_FORMAT_OPTIONS,
|
||||||
POST_BODY_FORMAT_TITLES,
|
POST_BODY_FORMAT_TITLES,
|
||||||
} from "constants/ApiEditorConstants";
|
} 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 KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
|
||||||
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
|
import DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
|
||||||
import { AppState } from "@appsmith/reducers";
|
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 DynamicTextField from "components/editorComponents/form/fields/DynamicTextField";
|
||||||
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
|
import KeyValueFieldArray from "components/editorComponents/form/fields/KeyValueFieldArray";
|
||||||
import ApiResponseView from "components/editorComponents/ApiResponseView";
|
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 CredentialsTooltip from "components/editorComponents/form/CredentialsTooltip";
|
||||||
import { FormIcons } from "icons/FormIcons";
|
import { FormIcons } from "icons/FormIcons";
|
||||||
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
|
import { BaseTabbedView } from "components/designSystems/appsmith/TabbedView";
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { DATASOURCE_DB_FORM } from "constants/forms";
|
import { DATASOURCE_DB_FORM } from "@appsmith/constants/forms";
|
||||||
import { Icon } from "@blueprintjs/core";
|
import { Icon } from "@blueprintjs/core";
|
||||||
import FormTitle from "./FormTitle";
|
import FormTitle from "./FormTitle";
|
||||||
import { Button, Category } from "design-system";
|
import { Button, Category } from "design-system";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { createNewApiName } from "utils/AppsmithUtils";
|
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 FormTitle from "./FormTitle";
|
||||||
import Button from "components/editorComponents/Button";
|
import Button from "components/editorComponents/Button";
|
||||||
import { Datasource } from "entities/Datasource";
|
import { Datasource } from "entities/Datasource";
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
switchDatasource,
|
switchDatasource,
|
||||||
setDatsourceEditorMode,
|
setDatsourceEditorMode,
|
||||||
} from "actions/datasourceActions";
|
} from "actions/datasourceActions";
|
||||||
import { DATASOURCE_DB_FORM } from "constants/forms";
|
import { DATASOURCE_DB_FORM } from "@appsmith/constants/forms";
|
||||||
import DataSourceEditorForm from "./DBForm";
|
import DataSourceEditorForm from "./DBForm";
|
||||||
import RestAPIDatasourceForm from "./RestAPIDatasourceForm";
|
import RestAPIDatasourceForm from "./RestAPIDatasourceForm";
|
||||||
import { Datasource } from "entities/Datasource";
|
import { Datasource } from "entities/Datasource";
|
||||||
|
|
@ -33,7 +33,7 @@ import {
|
||||||
REST_API_AUTHORIZATION_APPSMITH_ERROR,
|
REST_API_AUTHORIZATION_APPSMITH_ERROR,
|
||||||
REST_API_AUTHORIZATION_FAILED,
|
REST_API_AUTHORIZATION_FAILED,
|
||||||
REST_API_AUTHORIZATION_SUCCESSFUL,
|
REST_API_AUTHORIZATION_SUCCESSFUL,
|
||||||
} from "ce/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
import { Toaster } from "components/ads/Toast";
|
import { Toaster } from "components/ads/Toast";
|
||||||
import { Variant } from "components/ads/common";
|
import { Variant } from "components/ads/common";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,8 @@ import {
|
||||||
CLOSE_ENTITY_EXPLORER_MESSAGE,
|
CLOSE_ENTITY_EXPLORER_MESSAGE,
|
||||||
createMessage,
|
createMessage,
|
||||||
DEPLOY_BUTTON_TOOLTIP,
|
DEPLOY_BUTTON_TOOLTIP,
|
||||||
|
INVITE_USERS_MESSAGE,
|
||||||
|
INVITE_USERS_PLACEHOLDER,
|
||||||
LOCK_ENTITY_EXPLORER_MESSAGE,
|
LOCK_ENTITY_EXPLORER_MESSAGE,
|
||||||
LOGO_TOOLTIP,
|
LOGO_TOOLTIP,
|
||||||
RENAME_APPLICATION_TOOLTIP,
|
RENAME_APPLICATION_TOOLTIP,
|
||||||
|
|
@ -82,6 +84,7 @@ import EndTour from "./GuidedTour/EndTour";
|
||||||
import { GUIDED_TOUR_STEPS } from "./GuidedTour/constants";
|
import { GUIDED_TOUR_STEPS } from "./GuidedTour/constants";
|
||||||
import { viewerURL } from "RouteBuilder";
|
import { viewerURL } from "RouteBuilder";
|
||||||
import { useHref } from "./utils";
|
import { useHref } from "./utils";
|
||||||
|
import { inviteModalLinks } from "@appsmith/constants/forms";
|
||||||
|
|
||||||
const HeaderWrapper = styled.div`
|
const HeaderWrapper = styled.div`
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
@ -459,6 +462,9 @@ export function EditorHeader(props: EditorHeaderProps) {
|
||||||
bgColor: Colors.GEYSER_LIGHT,
|
bgColor: Colors.GEYSER_LIGHT,
|
||||||
}}
|
}}
|
||||||
isOpen={showAppInviteUsersDialog}
|
isOpen={showAppInviteUsersDialog}
|
||||||
|
links={inviteModalLinks}
|
||||||
|
message={createMessage(INVITE_USERS_MESSAGE)}
|
||||||
|
placeholder={createMessage(INVITE_USERS_PLACEHOLDER)}
|
||||||
title={
|
title={
|
||||||
currentApplication
|
currentApplication
|
||||||
? currentApplication.name
|
? currentApplication.name
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,10 @@ import { Colors } from "constants/Colors";
|
||||||
import { TOOLTIP_HOVER_ON_DELAY } from "constants/AppConstants";
|
import { TOOLTIP_HOVER_ON_DELAY } from "constants/AppConstants";
|
||||||
import { EntityClassNames } from "../Entity";
|
import { EntityClassNames } from "../Entity";
|
||||||
import { TooltipComponent } from "design-system";
|
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 { useCloseMenuOnScroll } from "../hooks";
|
||||||
import { SIDEBAR_ID } from "constants/Explorer";
|
import { SIDEBAR_ID } from "constants/Explorer";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { connect } from "react-redux";
|
||||||
import { initialize } from "redux-form";
|
import { initialize } from "redux-form";
|
||||||
import { getDBPlugins, getPluginImages } from "selectors/entitiesSelector";
|
import { getDBPlugins, getPluginImages } from "selectors/entitiesSelector";
|
||||||
import { Plugin } from "api/PluginApi";
|
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 { createDatasourceFromForm } from "actions/datasourceActions";
|
||||||
import { AppState } from "@appsmith/reducers";
|
import { AppState } from "@appsmith/reducers";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { connect } from "react-redux";
|
||||||
import { reduxForm, InjectedFormProps } from "redux-form";
|
import { reduxForm, InjectedFormProps } from "redux-form";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { AppState } from "@appsmith/reducers";
|
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 { Colors } from "constants/Colors";
|
||||||
import { TabComponent, TabProp } from "components/ads/Tabs";
|
import { TabComponent, TabProp } from "components/ads/Tabs";
|
||||||
import { IconSize } from "design-system";
|
import { IconSize } from "design-system";
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,10 @@ import {
|
||||||
StyledButton,
|
StyledButton,
|
||||||
TooltipComponent as Tooltip,
|
TooltipComponent as Tooltip,
|
||||||
} from "design-system";
|
} 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 { JSActionDropdownOption } from "./utils";
|
||||||
import { RUN_BUTTON_DEFAULTS, testLocators } from "./constants";
|
import { RUN_BUTTON_DEFAULTS, testLocators } from "./constants";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import {
|
||||||
ASYNC_FUNCTION_SETTINGS_HEADING,
|
ASYNC_FUNCTION_SETTINGS_HEADING,
|
||||||
createMessage,
|
createMessage,
|
||||||
NO_ASYNC_FUNCTIONS,
|
NO_ASYNC_FUNCTIONS,
|
||||||
} from "ce/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
import {
|
import {
|
||||||
AppIcon,
|
AppIcon,
|
||||||
Radio,
|
Radio,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { all } from "@redux-saga/core/effects";
|
import { all } from "@redux-saga/core/effects";
|
||||||
import { AppState } from "ce/reducers";
|
import { AppState } from "@appsmith/reducers";
|
||||||
import lodash from "lodash";
|
import lodash from "lodash";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { MemoryRouter } from "react-router-dom";
|
import { MemoryRouter } from "react-router-dom";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { IconNames } from "@blueprintjs/icons";
|
import { IconNames } from "@blueprintjs/icons";
|
||||||
import { Icon, IconSize } from "design-system";
|
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 styled from "styled-components";
|
||||||
import { Colors } from "constants/Colors";
|
import { Colors } from "constants/Colors";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { formValueSelector, reduxForm } from "redux-form";
|
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 { Action } from "entities/Action";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { AppState } from "@appsmith/reducers";
|
import { AppState } from "@appsmith/reducers";
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import {
|
||||||
getCurrentApplicationId,
|
getCurrentApplicationId,
|
||||||
getIsEditorInitialized,
|
getIsEditorInitialized,
|
||||||
} from "selectors/editorSelectors";
|
} 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 { Plugin, UIComponentTypes } from "api/PluginApi";
|
||||||
import { Datasource } from "entities/Datasource";
|
import { Datasource } from "entities/Datasource";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import _, { merge } from "lodash";
|
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 FormTitle from "pages/Editor/DataSourceEditor/FormTitle";
|
||||||
import { Button as AdsButton, Category } from "design-system";
|
import { Button as AdsButton, Category } from "design-system";
|
||||||
import { Datasource } from "entities/Datasource";
|
import { Datasource } from "entities/Datasource";
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
ERROR_MESSAGE_NAME_EMPTY,
|
ERROR_MESSAGE_NAME_EMPTY,
|
||||||
APLHANUMERIC_HYPHEN_SLASH_SPACE_ERROR,
|
APLHANUMERIC_HYPHEN_SLASH_SPACE_ERROR,
|
||||||
UNIQUE_NAME_ERROR,
|
UNIQUE_NAME_ERROR,
|
||||||
} from "ce/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
|
|
||||||
interface SaveThemeModalProps {
|
interface SaveThemeModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
SettingSubtype,
|
SettingSubtype,
|
||||||
} from "@appsmith/pages/AdminSettings/config/types";
|
} from "@appsmith/pages/AdminSettings/config/types";
|
||||||
import Accordion from "./Accordion";
|
import Accordion from "./Accordion";
|
||||||
import { SETTINGS_FORM_NAME } from "constants/forms";
|
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
|
||||||
import { reduxForm } from "redux-form";
|
import { reduxForm } from "redux-form";
|
||||||
|
|
||||||
let container: any = null;
|
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 React from "react";
|
||||||
import { Button, Category } from "design-system";
|
import { Button, Category } from "design-system";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import { FormGroup, SettingComponentProps } from "./Common";
|
||||||
import { FormTextFieldProps } from "components/ads/formFields/TextField";
|
import { FormTextFieldProps } from "components/ads/formFields/TextField";
|
||||||
import { Button, Category, Checkbox } from "design-system";
|
import { Button, Category, Checkbox } from "design-system";
|
||||||
import { useSelector } from "react-redux";
|
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 useOnUpgrade from "utils/hooks/useOnUpgrade";
|
||||||
import { EventName } from "utils/AnalyticsUtil";
|
import { EventName } from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { render, screen } from "test/testUtils";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
|
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
|
||||||
import Group from "./group";
|
import Group from "./group";
|
||||||
import { SETTINGS_FORM_NAME } from "constants/forms";
|
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
|
||||||
import { reduxForm } from "redux-form";
|
import { reduxForm } from "redux-form";
|
||||||
|
|
||||||
let container: any = null;
|
let container: any = null;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { render, screen } from "test/testUtils";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
|
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
|
||||||
import TagInputField from "./TagInputField";
|
import TagInputField from "./TagInputField";
|
||||||
import { SETTINGS_FORM_NAME } from "constants/forms";
|
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
|
||||||
import { reduxForm } from "redux-form";
|
import { reduxForm } from "redux-form";
|
||||||
|
|
||||||
let container: any = null;
|
let container: any = null;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import {
|
||||||
SettingSubtype,
|
SettingSubtype,
|
||||||
} from "@appsmith/pages/AdminSettings/config/types";
|
} from "@appsmith/pages/AdminSettings/config/types";
|
||||||
import TextInput from "./TextInput";
|
import TextInput from "./TextInput";
|
||||||
import { SETTINGS_FORM_NAME } from "constants/forms";
|
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
|
||||||
import { reduxForm } from "redux-form";
|
import { reduxForm } from "redux-form";
|
||||||
|
|
||||||
let container: any = null;
|
let container: any = null;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { render } from "test/testUtils";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
|
import { SettingTypes } from "@appsmith/pages/AdminSettings/config/types";
|
||||||
import Toggle from "./Toggle";
|
import Toggle from "./Toggle";
|
||||||
import { SETTINGS_FORM_NAME } from "constants/forms";
|
import { SETTINGS_FORM_NAME } from "@appsmith/constants/forms";
|
||||||
import { reduxForm } from "redux-form";
|
import { reduxForm } from "redux-form";
|
||||||
|
|
||||||
let container: any = null;
|
let container: any = null;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import Toggle from "./Toggle";
|
||||||
import Text from "./Text";
|
import Text from "./Text";
|
||||||
import Button from "./Button";
|
import Button from "./Button";
|
||||||
import { getFormValues } from "redux-form";
|
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 { useSelector } from "store";
|
||||||
import {
|
import {
|
||||||
createMessage,
|
createMessage,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import React, { useCallback, useEffect } from "react";
|
import React, { useCallback, useEffect } from "react";
|
||||||
import { saveSettings } from "@appsmith/actions/settingsAction";
|
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 { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import ProductUpdatesModal from "pages/Applications/ProductUpdatesModal";
|
import ProductUpdatesModal from "pages/Applications/ProductUpdatesModal";
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import {
|
||||||
} from "@appsmith/constants/messages";
|
} from "@appsmith/constants/messages";
|
||||||
import { AUTH_LOGIN_URL } from "constants/routes";
|
import { AUTH_LOGIN_URL } from "constants/routes";
|
||||||
import FormMessage from "components/ads/formFields/FormMessage";
|
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 FormGroup from "components/ads/formFields/FormGroup";
|
||||||
import { Button, Size } from "design-system";
|
import { Button, Size } from "design-system";
|
||||||
import FormTextField from "components/ads/formFields/TextField";
|
import FormTextField from "components/ads/formFields/TextField";
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { AppState } from "@appsmith/reducers";
|
||||||
import { withRouter, RouteComponentProps } from "react-router-dom";
|
import { withRouter, RouteComponentProps } from "react-router-dom";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { InjectedFormProps, reduxForm, Field } from "redux-form";
|
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 { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { getIsTokenValid, getIsValidatingToken } from "selectors/authSelectors";
|
import { getIsTokenValid, getIsValidatingToken } from "selectors/authSelectors";
|
||||||
import { Icon } from "@blueprintjs/core";
|
import { Icon } from "@blueprintjs/core";
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import {
|
||||||
WELCOME_FORM_ROLE_NAME_FIELD_NAME,
|
WELCOME_FORM_ROLE_NAME_FIELD_NAME,
|
||||||
WELCOME_FORM_USECASE_FIELD_NAME,
|
WELCOME_FORM_USECASE_FIELD_NAME,
|
||||||
WELCOME_NON_SUPER_FORM_NAME,
|
WELCOME_NON_SUPER_FORM_NAME,
|
||||||
} from "constants/forms";
|
} from "@appsmith/constants/forms";
|
||||||
import {
|
import {
|
||||||
createMessage,
|
createMessage,
|
||||||
WELCOME_ACTION,
|
WELCOME_ACTION,
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import {
|
||||||
WELCOME_FORM_ROLE_NAME_FIELD_NAME,
|
WELCOME_FORM_ROLE_NAME_FIELD_NAME,
|
||||||
WELCOME_FORM_VERIFY_PASSWORD_FIELD_NAME,
|
WELCOME_FORM_VERIFY_PASSWORD_FIELD_NAME,
|
||||||
WELCOME_FORM_CUSTOM_USECASE_FIELD_NAME,
|
WELCOME_FORM_CUSTOM_USECASE_FIELD_NAME,
|
||||||
} from "constants/forms";
|
} from "@appsmith/constants/forms";
|
||||||
import {
|
import {
|
||||||
FormErrors,
|
FormErrors,
|
||||||
formValueSelector,
|
formValueSelector,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import {
|
||||||
} from "../Applications/permissionHelpers";
|
} from "../Applications/permissionHelpers";
|
||||||
import WorkspaceInviteUsersForm, {
|
import WorkspaceInviteUsersForm, {
|
||||||
InviteButtonWidth,
|
InviteButtonWidth,
|
||||||
} from "./WorkspaceInviteUsersForm";
|
} from "@appsmith/pages/workspace/WorkspaceInviteUsersForm";
|
||||||
import { getCurrentUser } from "selectors/usersSelectors";
|
import { getCurrentUser } from "selectors/usersSelectors";
|
||||||
import { Text, TextType, Toggle } from "design-system";
|
import { Text, TextType, Toggle } from "design-system";
|
||||||
import { ANONYMOUS_USERNAME } from "constants/userConstants";
|
import { ANONYMOUS_USERNAME } from "constants/userConstants";
|
||||||
|
|
@ -63,6 +63,7 @@ function AppInviteUsersForm(props: any) {
|
||||||
fetchCurrentWorkspace,
|
fetchCurrentWorkspace,
|
||||||
isChangingViewAccess,
|
isChangingViewAccess,
|
||||||
isFetchingApplication,
|
isFetchingApplication,
|
||||||
|
links,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const currentWorkspaceId = useSelector(getCurrentWorkspaceId);
|
const currentWorkspaceId = useSelector(getCurrentWorkspaceId);
|
||||||
|
|
@ -124,6 +125,7 @@ function AppInviteUsersForm(props: any) {
|
||||||
{canInviteToWorkspace && (
|
{canInviteToWorkspace && (
|
||||||
<WorkspaceInviteUsersForm
|
<WorkspaceInviteUsersForm
|
||||||
isApplicationInvite
|
isApplicationInvite
|
||||||
|
links={links}
|
||||||
workspaceId={props.workspaceId}
|
workspaceId={props.workspaceId}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
import React, { useCallback } from "react";
|
import React, { useCallback } from "react";
|
||||||
import { Form, reduxForm, InjectedFormProps } from "redux-form";
|
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 {
|
import {
|
||||||
CreateWorkspaceFormValues,
|
CreateWorkspaceFormValues,
|
||||||
createWorkspaceSubmitHandler,
|
createWorkspaceSubmitHandler,
|
||||||
} from "./helpers";
|
} from "@appsmith/pages/workspace/helpers";
|
||||||
import { noSpaces } from "utils/formhelpers";
|
import { noSpaces } from "utils/formhelpers";
|
||||||
import TextField from "components/editorComponents/form/fields/TextField";
|
import TextField from "components/editorComponents/form/fields/TextField";
|
||||||
import FormGroup from "components/editorComponents/form/FormGroup";
|
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 { BackButton, StickyHeader } from "components/utils/helperComponents";
|
||||||
import { debounce } from "lodash";
|
import { debounce } from "lodash";
|
||||||
import FormDialogComponent from "components/editorComponents/form/FormDialogComponent";
|
import FormDialogComponent from "components/editorComponents/form/FormDialogComponent";
|
||||||
import WorkspaceInviteUsersForm from "./WorkspaceInviteUsersForm";
|
import WorkspaceInviteUsersForm from "@appsmith/pages/workspace/WorkspaceInviteUsersForm";
|
||||||
import { SettingsPageHeader } from "./SettingsPageHeader";
|
import { SettingsPageHeader } from "./SettingsPageHeader";
|
||||||
import { navigateToTab } from "./helpers";
|
import { navigateToTab } from "@appsmith/pages/workspace/helpers";
|
||||||
|
|
||||||
const SentryRoute = Sentry.withSentryRouting(Route);
|
const SentryRoute = Sentry.withSentryRouting(Route);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import {
|
||||||
ReduxActionTypes,
|
ReduxActionTypes,
|
||||||
ReduxAction,
|
ReduxAction,
|
||||||
ReduxActionErrorTypes,
|
ReduxActionErrorTypes,
|
||||||
} from "ce/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { set, keyBy, findIndex, unset } from "lodash";
|
import { set, keyBy, findIndex, unset } from "lodash";
|
||||||
import produce from "immer";
|
import produce from "immer";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import editorReducer from "./editorReducer";
|
||||||
import errorReducer from "./errorReducer";
|
import errorReducer from "./errorReducer";
|
||||||
import propertyPaneReducer from "./propertyPaneReducer";
|
import propertyPaneReducer from "./propertyPaneReducer";
|
||||||
import appViewReducer from "./appViewReducer";
|
import appViewReducer from "./appViewReducer";
|
||||||
import applicationsReducer from "./applicationsReducer";
|
import applicationsReducer from "@appsmith/reducers/uiReducers/applicationsReducer";
|
||||||
import apiPaneReducer from "./apiPaneReducer";
|
import apiPaneReducer from "./apiPaneReducer";
|
||||||
import datasourcePaneReducer from "./datasourcePaneReducer";
|
import datasourcePaneReducer from "./datasourcePaneReducer";
|
||||||
import authReducer from "./authReducer";
|
import authReducer from "./authReducer";
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ import {
|
||||||
import { requestModalConfirmationSaga } from "sagas/UtilSagas";
|
import { requestModalConfirmationSaga } from "sagas/UtilSagas";
|
||||||
import { ModalType } from "reducers/uiReducers/modalActionReducer";
|
import { ModalType } from "reducers/uiReducers/modalActionReducer";
|
||||||
import { getFormNames, getFormValues } from "redux-form";
|
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 { submitCurlImportForm } from "actions/importActions";
|
||||||
import { curlImportFormValues } from "pages/Editor/APIEditor/helpers";
|
import { curlImportFormValues } from "pages/Editor/APIEditor/helpers";
|
||||||
import { matchBasePath } from "pages/Editor/Explorer/helpers";
|
import { matchBasePath } from "pages/Editor/Explorer/helpers";
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,10 @@ import {
|
||||||
ReduxFormActionTypes,
|
ReduxFormActionTypes,
|
||||||
} from "@appsmith/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { GetFormData, getFormData } from "selectors/formSelectors";
|
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 {
|
import {
|
||||||
DEFAULT_API_ACTION_CONFIG,
|
DEFAULT_API_ACTION_CONFIG,
|
||||||
POST_BODY_FORMAT_OPTIONS_ARRAY,
|
POST_BODY_FORMAT_OPTIONS_ARRAY,
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ import {
|
||||||
API_EDITOR_FORM_NAME,
|
API_EDITOR_FORM_NAME,
|
||||||
DATASOURCE_DB_FORM,
|
DATASOURCE_DB_FORM,
|
||||||
DATASOURCE_REST_API_FORM,
|
DATASOURCE_REST_API_FORM,
|
||||||
} from "constants/forms";
|
} from "@appsmith/constants/forms";
|
||||||
import { validateResponse } from "./ErrorSagas";
|
import { validateResponse } from "./ErrorSagas";
|
||||||
import AnalyticsUtil from "utils/AnalyticsUtil";
|
import AnalyticsUtil from "utils/AnalyticsUtil";
|
||||||
import { getFormData } from "selectors/formSelectors";
|
import { getFormData } from "selectors/formSelectors";
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,10 @@ import {
|
||||||
ReduxFormActionTypes,
|
ReduxFormActionTypes,
|
||||||
} from "@appsmith/constants/ReduxActionConstants";
|
} from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { getFormData } from "selectors/formSelectors";
|
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 history from "utils/history";
|
||||||
import { APPLICATIONS_URL, INTEGRATION_TABS } from "constants/routes";
|
import { APPLICATIONS_URL, INTEGRATION_TABS } from "constants/routes";
|
||||||
import {
|
import {
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,7 @@ import {
|
||||||
DATASOURCE_DB_FORM,
|
DATASOURCE_DB_FORM,
|
||||||
DATASOURCE_REST_API_FORM,
|
DATASOURCE_REST_API_FORM,
|
||||||
QUERY_EDITOR_FORM_NAME,
|
QUERY_EDITOR_FORM_NAME,
|
||||||
} from "constants/forms";
|
} from "@appsmith/constants/forms";
|
||||||
import { Canvas } from "entities/Replay/ReplayEntity/ReplayCanvas";
|
import { Canvas } from "entities/Replay/ReplayEntity/ReplayCanvas";
|
||||||
import {
|
import {
|
||||||
setAppThemingModeStackAction,
|
setAppThemingModeStackAction,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { ReduxActionTypes } from "ce/constants/ReduxActionConstants";
|
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { APP_MODE } from "entities/App";
|
import { APP_MODE } from "entities/App";
|
||||||
import AppEngine from "entities/Engine";
|
import AppEngine from "entities/Engine";
|
||||||
import AppEngineFactory from "entities/Engine/factory";
|
import AppEngineFactory from "entities/Engine/factory";
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { AppState } from "@appsmith/reducers";
|
||||||
import {
|
import {
|
||||||
ApplicationsReduxState,
|
ApplicationsReduxState,
|
||||||
creatingApplicationMap,
|
creatingApplicationMap,
|
||||||
} from "reducers/uiReducers/applicationsReducer";
|
} from "@appsmith/reducers/uiReducers/applicationsReducer";
|
||||||
import {
|
import {
|
||||||
ApplicationPayload,
|
ApplicationPayload,
|
||||||
WorkspaceDetails,
|
WorkspaceDetails,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { getAppsmithConfigs } from "ce/configs";
|
import { getAppsmithConfigs } from "@appsmith/configs";
|
||||||
import FormControlRegistry from "./formControl/FormControlRegistry";
|
import FormControlRegistry from "./formControl/FormControlRegistry";
|
||||||
import { LogLevelDesc } from "loglevel";
|
import { LogLevelDesc } from "loglevel";
|
||||||
import localStorage from "utils/localStorage";
|
import localStorage from "utils/localStorage";
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
import { getAppsmithConfigs } from "@appsmith/configs";
|
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";
|
import AnalyticsUtil, { EventName } from "utils/AnalyticsUtil";
|
||||||
|
|
||||||
const { intercomAppID } = getAppsmithConfigs();
|
const { intercomAppID } = getAppsmithConfigs();
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import {
|
||||||
FormConfigEvalObject,
|
FormConfigEvalObject,
|
||||||
DynamicValuesConfig,
|
DynamicValuesConfig,
|
||||||
} from "reducers/evaluationReducers/formEvaluationReducer";
|
} from "reducers/evaluationReducers/formEvaluationReducer";
|
||||||
import { ReduxActionTypes } from "ce/constants/ReduxActionConstants";
|
import { ReduxActionTypes } from "@appsmith/constants/ReduxActionConstants";
|
||||||
import { ActionConfig } from "entities/Action";
|
import { ActionConfig } from "entities/Action";
|
||||||
import { FormEvalActionPayload } from "sagas/FormEvaluationSaga";
|
import { FormEvalActionPayload } from "sagas/FormEvaluationSaga";
|
||||||
import { FormConfigType } from "components/formControls/BaseControl";
|
import { FormConfigType } from "components/formControls/BaseControl";
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import initSagas from "../src/sagas/InitSagas";
|
import initSagas from "../src/sagas/InitSagas";
|
||||||
import apiPaneSagas from "../src/sagas/ApiPaneSagas";
|
import apiPaneSagas from "../src/sagas/ApiPaneSagas";
|
||||||
import jsPaneSagas from "../src/sagas/JSPaneSagas";
|
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 pluginSagas from "../src/sagas/PluginSagas";
|
||||||
import workspaceSagas from "../src/sagas/WorkspaceSagas";
|
import workspaceSagas from "../src/sagas/WorkspaceSagas";
|
||||||
import importedCollectionsSagas from "../src/sagas/CollectionSagas";
|
import importedCollectionsSagas from "../src/sagas/CollectionSagas";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user