From c7d8b48d7250edbf5c83311a93da33ace212b0fe Mon Sep 17 00:00:00 2001 From: "Mahatthana (Kelvin) Nomsawadi" <mahatthana.n@gmail.com> Date: Wed, 20 Jul 2022 14:49:30 +0700 Subject: [PATCH] Fix rendering segment and metric revision history (#24097) * Fix rendering segment and metric revision history * Address Alexander's feedback * Remove unused styled-system props --- .../components/UserAvatar/UserAvatar.jsx | 54 -------------- .../UserAvatar/UserAvatar.styled.tsx | 22 ++++++ .../components/UserAvatar/UserAvatar.tsx | 64 +++++++++++++++++ .../UserAvatar/UserAvatar.unit.spec.tsx | 71 +++++++++++++++++++ 4 files changed, 157 insertions(+), 54 deletions(-) delete mode 100644 frontend/src/metabase/components/UserAvatar/UserAvatar.jsx create mode 100644 frontend/src/metabase/components/UserAvatar/UserAvatar.styled.tsx create mode 100644 frontend/src/metabase/components/UserAvatar/UserAvatar.tsx create mode 100644 frontend/src/metabase/components/UserAvatar/UserAvatar.unit.spec.tsx diff --git a/frontend/src/metabase/components/UserAvatar/UserAvatar.jsx b/frontend/src/metabase/components/UserAvatar/UserAvatar.jsx deleted file mode 100644 index e7a9dcf6a74..00000000000 --- a/frontend/src/metabase/components/UserAvatar/UserAvatar.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/* eslint-disable react/prop-types */ -import React from "react"; -import styled from "@emotion/styled"; -import { color, height, width } from "styled-system"; - -import { color as brandColor } from "metabase/lib/colors"; - -const Avatar = styled.div` - display: flex; - justify-content: center; - align-items: center; - border-radius: 999px; - font-weight: 900; - line-height: 1; - ${height}; - ${width}; - ${color}; - background-color: ${({ bg = brandColor("brand") }) => bg}; -`; - -Avatar.defaultProps = { - color: "white", - height: ["3em"], - width: ["3em"], -}; - -function initial(name) { - return typeof name === "string" ? name.charAt(0).toUpperCase() : ""; -} - -function userInitials(user) { - if (user) { - return nameInitials(user) || emailInitials(user); - } - - return null; -} - -function nameInitials(user) { - return initial(user.first_name) + initial(user.last_name); -} - -function emailInitials(user) { - const emailUsername = user.email.split("@")[0]; - return emailUsername.slice(0, 2).toUpperCase(); -} - -const UserAvatar = ({ user, ...props }) => ( - <Avatar {...props}>{userInitials(user) || "?"}</Avatar> -); - -UserAvatar.displayName = "UserAvatar"; - -export default UserAvatar; diff --git a/frontend/src/metabase/components/UserAvatar/UserAvatar.styled.tsx b/frontend/src/metabase/components/UserAvatar/UserAvatar.styled.tsx new file mode 100644 index 00000000000..ef9ecf9308e --- /dev/null +++ b/frontend/src/metabase/components/UserAvatar/UserAvatar.styled.tsx @@ -0,0 +1,22 @@ +import styled from "@emotion/styled"; +import { color as brandColor, color } from "metabase/lib/colors"; + +export interface AvatarProps { + color?: string; + height?: string[]; + width?: string[]; + bg?: string; +} + +export const Avatar = styled.div<AvatarProps>` + color: ${color("white")}; + width: 3em; + height: 3em; + display: flex; + justify-content: center; + align-items: center; + border-radius: 999px; + font-weight: 900; + line-height: 1; + background-color: ${({ bg = brandColor("brand") }) => bg}; +`; diff --git a/frontend/src/metabase/components/UserAvatar/UserAvatar.tsx b/frontend/src/metabase/components/UserAvatar/UserAvatar.tsx new file mode 100644 index 00000000000..a88200adbdc --- /dev/null +++ b/frontend/src/metabase/components/UserAvatar/UserAvatar.tsx @@ -0,0 +1,64 @@ +/* eslint-disable react/prop-types */ +import React from "react"; + +import MetabaseUtils from "metabase/lib/utils"; +import { Avatar, AvatarProps } from "./UserAvatar.styled"; + +interface UserAvatarProps extends AvatarProps { + user: User; +} + +interface GroupProps { + user: Group; +} + +interface User { + first_name: string | null; + last_name: string | null; + common_name: string; + email?: string; +} + +interface Group { + first_name: string; +} + +export default function UserAvatar({ + user, + ...props +}: UserAvatarProps | GroupProps) { + return <Avatar {...props}>{userInitials(user) || "?"}</Avatar>; +} + +function initial(name?: string | null) { + return name ? name.charAt(0).toUpperCase() : ""; +} + +function userInitials(user: User | Group) { + if (user) { + return nameInitials(user) || emailInitials(user as User); + } + + return null; +} + +function nameInitials(user: User | Group) { + if ("common_name" in user) { + return initial(user.first_name) + initial(user.last_name); + } + + // render group + return initial(user.first_name); +} + +function emailInitials(user: User) { + const email = [user.email, user.common_name].find(maybeEmail => + MetabaseUtils.isEmail(maybeEmail), + ); + if (email) { + const emailUsername = email.split("@")[0]; + return emailUsername.slice(0, 2).toUpperCase(); + } + + return null; +} diff --git a/frontend/src/metabase/components/UserAvatar/UserAvatar.unit.spec.tsx b/frontend/src/metabase/components/UserAvatar/UserAvatar.unit.spec.tsx new file mode 100644 index 00000000000..479fadbc249 --- /dev/null +++ b/frontend/src/metabase/components/UserAvatar/UserAvatar.unit.spec.tsx @@ -0,0 +1,71 @@ +import React from "react"; +import { render } from "@testing-library/react"; +import UserAvatar from "./UserAvatar"; + +describe("UserAvatar", () => { + describe("Users", () => { + test("render user with name", async () => { + const revisionUser = { + first_name: "Testy", + last_name: "Tableton", + common_name: "Testy Tableton", + email: "user@metabase.test", + }; + + const { findByText } = render(<UserAvatar user={revisionUser} />); + + expect(await findByText("TT")).toBeInTheDocument(); + }); + + test("render user without name", async () => { + const revisionUser = { + first_name: null, + last_name: null, + common_name: "user@metabase.test", + email: "user@metabase.test", + }; + + const { findByText } = render(<UserAvatar user={revisionUser} />); + + expect(await findByText("US")).toBeInTheDocument(); + }); + }); + + describe("Revision history", () => { + test("render user with name", async () => { + const revisionUser = { + first_name: "Testy", + last_name: "Tableton", + common_name: "Testy Tableton", + }; + + const { findByText } = render(<UserAvatar user={revisionUser} />); + + expect(await findByText("TT")).toBeInTheDocument(); + }); + + test("render user without name", async () => { + const revisionUser = { + first_name: null, + last_name: null, + common_name: "user@metabase.test", + }; + + const { findByText } = render(<UserAvatar user={revisionUser} />); + + expect(await findByText("US")).toBeInTheDocument(); + }); + }); + + describe("Admin > Groups", () => { + test("render group name", async () => { + const revisionUser = { + first_name: "Admin", + }; + + const { findByText } = render(<UserAvatar user={revisionUser} />); + + expect(await findByText("A")).toBeInTheDocument(); + }); + }); +}); -- GitLab