Feature: Show org user icons on homepage (#1685)
* Displaying org user icons feature is implemented * using username if name not found in user details * Share user icon cypress test implemented
This commit is contained in:
parent
a4f652ce70
commit
73869eee69
|
|
@ -0,0 +1,25 @@
|
|||
/// <reference types="Cypress" />
|
||||
|
||||
const homePage = require("../../../locators/HomePage.json");
|
||||
|
||||
describe("Check if org has user icons on homepage", function() {
|
||||
let orgid;
|
||||
|
||||
it("create org and check if user icons exists in that org on homepage", function() {
|
||||
cy.NavigateToHome();
|
||||
cy.generateUUID().then(uid => {
|
||||
orgid = uid;
|
||||
localStorage.setItem("OrgName", orgid);
|
||||
cy.createOrg(orgid);
|
||||
cy.get(homePage.orgList.concat(orgid).concat(")"))
|
||||
.scrollIntoView()
|
||||
.should("be.visible")
|
||||
.within(() => {
|
||||
cy.get(homePage.shareUserIcons)
|
||||
.first()
|
||||
.should("be.visible");
|
||||
});
|
||||
});
|
||||
cy.LogOut();
|
||||
});
|
||||
});
|
||||
|
|
@ -61,5 +61,6 @@
|
|||
"orgWebsiteInput": "[data-cy=t--org-website-input]",
|
||||
"orgHeaderName": ".t--organization-header",
|
||||
"leftPanelContainer": "[data-cy=t--left-panel]",
|
||||
"themeText": "label div"
|
||||
"themeText": "label div",
|
||||
"shareUserIcons": ".org-share-user-icons"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,12 +83,19 @@ export interface ApplicationObject {
|
|||
userPermissions: string[];
|
||||
}
|
||||
|
||||
export interface UserRoles {
|
||||
name: string;
|
||||
roleName: string;
|
||||
username: string;
|
||||
}
|
||||
|
||||
export interface OrganizationApplicationObject {
|
||||
applications: Array<ApplicationObject>;
|
||||
organization: {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
userRoles: Array<UserRoles>;
|
||||
}
|
||||
export interface FetchUsersApplicationsOrgsResponse extends ApiResponse {
|
||||
data: {
|
||||
|
|
|
|||
|
|
@ -28,10 +28,7 @@ import FormDialogComponent from "components/editorComponents/form/FormDialogComp
|
|||
import { User } from "constants/userConstants";
|
||||
import { getCurrentUser } from "selectors/usersSelectors";
|
||||
import CreateOrganizationForm from "pages/organization/CreateOrganizationForm";
|
||||
import {
|
||||
CREATE_ORGANIZATION_FORM_NAME,
|
||||
CREATE_APPLICATION_FORM_NAME,
|
||||
} from "constants/forms";
|
||||
import { CREATE_ORGANIZATION_FORM_NAME } from "constants/forms";
|
||||
import {
|
||||
getOnSelectAction,
|
||||
DropdownOnSelectActions,
|
||||
|
|
@ -48,7 +45,7 @@ import { Classes } from "components/ads/common";
|
|||
import Menu from "components/ads/Menu";
|
||||
import { Position } from "@blueprintjs/core/lib/esm/common/position";
|
||||
import HelpModal from "components/designSystems/appsmith/help/HelpModal";
|
||||
import { UpdateApplicationPayload } from "api/ApplicationApi";
|
||||
import { UpdateApplicationPayload, UserRoles } from "api/ApplicationApi";
|
||||
import PerformanceTracker, {
|
||||
PerformanceTransactionName,
|
||||
} from "utils/PerformanceTracker";
|
||||
|
|
@ -58,6 +55,7 @@ import CenteredWrapper from "../../components/designSystems/appsmith/CenteredWra
|
|||
import NoSearchImage from "../../assets/images/NoSearchResult.svg";
|
||||
import { getNextEntityName } from "utils/AppsmithUtils";
|
||||
import Spinner from "components/ads/Spinner";
|
||||
import ProfileImage from "pages/common/ProfileImage";
|
||||
|
||||
const OrgDropDown = styled.div`
|
||||
display: flex;
|
||||
|
|
@ -193,6 +191,25 @@ const ItemWrapper = styled.div`
|
|||
const StyledIcon = styled(Icon)`
|
||||
margin-right: 11px;
|
||||
`;
|
||||
const UserImageContainer = styled.div`
|
||||
display: flex;
|
||||
margin-right: 8px;
|
||||
|
||||
div {
|
||||
cursor: default;
|
||||
margin-right: -6px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
div:last-child {
|
||||
margin-right: 0px;
|
||||
}
|
||||
`;
|
||||
const OrgShareUsers = styled.div`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
function Item(props: {
|
||||
label: string;
|
||||
|
|
@ -536,7 +553,7 @@ const ApplicationsSection = (props: any) => {
|
|||
} else {
|
||||
organizationsListComponent = updatedOrgs.map(
|
||||
(organizationObject: any, index: number) => {
|
||||
const { organization, applications } = organizationObject;
|
||||
const { organization, applications, userRoles } = organizationObject;
|
||||
const hasManageOrgPermissions = isPermitted(
|
||||
organization.userPermissions,
|
||||
PERMISSION_TYPE.MANAGE_ORGANIZATION,
|
||||
|
|
@ -572,15 +589,30 @@ const ApplicationsSection = (props: any) => {
|
|||
PERMISSION_TYPE.INVITE_USER_TO_ORGANIZATION,
|
||||
) &&
|
||||
!isFetchingApplications && (
|
||||
<FormDialogComponent
|
||||
trigger={
|
||||
<Button text={"Share"} icon={"share"} size={Size.small} />
|
||||
}
|
||||
canOutsideClickClose={true}
|
||||
Form={OrgInviteUsersForm}
|
||||
orgId={organization.id}
|
||||
title={`Invite Users to ${organization.name}`}
|
||||
/>
|
||||
<OrgShareUsers>
|
||||
<UserImageContainer>
|
||||
{userRoles.map((el: UserRoles) => (
|
||||
<ProfileImage
|
||||
className="org-share-user-icons"
|
||||
userName={el.name ? el.name : el.username}
|
||||
key={el.username}
|
||||
/>
|
||||
))}
|
||||
</UserImageContainer>
|
||||
<FormDialogComponent
|
||||
trigger={
|
||||
<Button
|
||||
text={"Share"}
|
||||
icon={"share"}
|
||||
size={Size.small}
|
||||
/>
|
||||
}
|
||||
canOutsideClickClose={true}
|
||||
Form={OrgInviteUsersForm}
|
||||
orgId={organization.id}
|
||||
title={`Invite Users to ${organization.name}`}
|
||||
/>
|
||||
</OrgShareUsers>
|
||||
)}
|
||||
</OrgDropDown>
|
||||
<ApplicationCardsWrapper key={organization.id}>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
import React, { Fragment } from "react";
|
||||
import { CommonComponentProps, Classes } from "components/ads/common";
|
||||
import { getInitialsAndColorCode } from "utils/AppsmithUtils";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getThemeDetails } from "selectors/themeSelectors";
|
||||
import Text, { TextType } from "components/ads/Text";
|
||||
import styled, { createGlobalStyle } from "styled-components";
|
||||
import { Position } from "@blueprintjs/core";
|
||||
|
|
@ -15,23 +12,13 @@ import {
|
|||
DropdownOnSelectActions,
|
||||
} from "./CustomizedDropdown/dropdownHelpers";
|
||||
import { ReduxActionTypes } from "constants/ReduxActionConstants";
|
||||
import ProfileImage from "./ProfileImage";
|
||||
|
||||
type TagProps = CommonComponentProps & {
|
||||
onClick?: (text: string) => void;
|
||||
userName?: string;
|
||||
};
|
||||
|
||||
export const ProfileImage = styled.div<{ backgroundColor?: string }>`
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
background-color: ${props => props.backgroundColor};
|
||||
`;
|
||||
|
||||
const ProfileMenuStyle = createGlobalStyle`
|
||||
.bp3-popover {
|
||||
box-shadow: none;
|
||||
|
|
@ -67,20 +54,8 @@ const UserInformation = styled.div`
|
|||
`;
|
||||
|
||||
export default function ProfileDropdown(props: TagProps) {
|
||||
const themeDetails = useSelector(getThemeDetails);
|
||||
const Profile = <ProfileImage userName={props.userName} />;
|
||||
|
||||
const initialsAndColorCode = getInitialsAndColorCode(
|
||||
props.userName,
|
||||
themeDetails.theme.colors.appCardColors,
|
||||
);
|
||||
|
||||
const Profile = (
|
||||
<ProfileImage backgroundColor={initialsAndColorCode[1]}>
|
||||
<Text type={TextType.H6} highlight>
|
||||
{initialsAndColorCode[0]}
|
||||
</Text>
|
||||
</ProfileImage>
|
||||
);
|
||||
return (
|
||||
<Fragment>
|
||||
<ProfileMenuStyle />
|
||||
|
|
|
|||
40
app/client/src/pages/common/ProfileImage.tsx
Normal file
40
app/client/src/pages/common/ProfileImage.tsx
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
import React from "react";
|
||||
import { useSelector } from "react-redux";
|
||||
import { getThemeDetails } from "selectors/themeSelectors";
|
||||
import { getInitialsAndColorCode } from "utils/AppsmithUtils";
|
||||
import Text, { TextType } from "components/ads/Text";
|
||||
import styled from "styled-components";
|
||||
|
||||
export const Profile = styled.div<{ backgroundColor?: string }>`
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
background-color: ${props => props.backgroundColor};
|
||||
`;
|
||||
|
||||
export default function ProfileImage(props: {
|
||||
userName?: string;
|
||||
className?: string;
|
||||
}) {
|
||||
const themeDetails = useSelector(getThemeDetails);
|
||||
|
||||
const initialsAndColorCode = getInitialsAndColorCode(
|
||||
props.userName,
|
||||
themeDetails.theme.colors.appCardColors,
|
||||
);
|
||||
|
||||
return (
|
||||
<Profile
|
||||
backgroundColor={initialsAndColorCode[1]}
|
||||
className={props.className}
|
||||
>
|
||||
<Text type={TextType.H6} highlight>
|
||||
{initialsAndColorCode[0]}
|
||||
</Text>
|
||||
</Profile>
|
||||
);
|
||||
}
|
||||
|
|
@ -38,8 +38,8 @@ import { Classes } from "components/ads/common";
|
|||
import Callout from "components/ads/Callout";
|
||||
import { getInitialsAndColorCode } from "utils/AppsmithUtils";
|
||||
import { getThemeDetails } from "selectors/themeSelectors";
|
||||
import { ProfileImage } from "pages/common/ProfileDropdown";
|
||||
import { scrollbarDark } from "constants/DefaultTheme";
|
||||
import ProfileImage from "pages/common/ProfileImage";
|
||||
|
||||
const OrgInviteTitle = styled.div`
|
||||
padding: 10px 0px;
|
||||
|
|
@ -280,7 +280,6 @@ const OrgInviteUsersForm = (props: any) => {
|
|||
);
|
||||
return {
|
||||
...user,
|
||||
imageBackground: details[1],
|
||||
initials: details[0],
|
||||
};
|
||||
},
|
||||
|
|
@ -358,18 +357,13 @@ const OrgInviteUsersForm = (props: any) => {
|
|||
username: string;
|
||||
name: string;
|
||||
roleName: string;
|
||||
imageBackground: string;
|
||||
initials: string;
|
||||
}) => {
|
||||
return (
|
||||
<Fragment key={user.username}>
|
||||
<User>
|
||||
<UserInfo>
|
||||
<ProfileImage backgroundColor={user.imageBackground}>
|
||||
<Text type={TextType.H6} highlight>
|
||||
{user.initials}
|
||||
</Text>
|
||||
</ProfileImage>
|
||||
<ProfileImage userName={user.initials} />
|
||||
<UserName>
|
||||
<Text type={TextType.H5}>{user.name}</Text>
|
||||
<Text type={TextType.P2}>{user.username}</Text>
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ export function* getAllApplicationSaga() {
|
|||
const organizationApplication: OrganizationApplicationObject[] = response.data.organizationApplications.map(
|
||||
(userOrgs: OrganizationApplicationObject) => ({
|
||||
organization: userOrgs.organization,
|
||||
userRoles: userOrgs.userRoles,
|
||||
applications: !userOrgs.applications
|
||||
? []
|
||||
: userOrgs.applications.map((application: ApplicationObject) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user