Просмотр исходного кода

ref(badge): improve types (#42159)

~Lets see how much hell breaks loose here~. Improves the ts types of the
badge component so we can drop the & Record<string, any>... Next part
I'll look at making project/team/member actually required when passing
it as a prop
Jonas 2 лет назад
Родитель
Сommit
3b33254aea

+ 3 - 3
static/app/components/idBadge/baseBadge.tsx

@@ -5,7 +5,7 @@ import Avatar from 'sentry/components/avatar';
 import space from 'sentry/styles/space';
 import {AvatarProject, Organization, Team} from 'sentry/types';
 
-type Props = {
+export interface BaseBadgeProps {
   displayName: React.ReactNode;
   avatarProps?: Record<string, any>;
   avatarSize?: number;
@@ -17,7 +17,7 @@ type Props = {
   organization?: Organization;
   project?: AvatarProject;
   team?: Team;
-};
+}
 
 const BaseBadge = memo(
   ({
@@ -31,7 +31,7 @@ const BaseBadge = memo(
     organization,
     project,
     className,
-  }: Props) => (
+  }: BaseBadgeProps) => (
     <Wrapper className={className}>
       {!hideAvatar && (
         <StyledAvatar

+ 52 - 28
static/app/components/idBadge/getBadge.tsx

@@ -1,42 +1,66 @@
-import BaseBadge from 'sentry/components/idBadge/baseBadge';
-import MemberBadge from 'sentry/components/idBadge/memberBadge';
-import OrganizationBadge from 'sentry/components/idBadge/organizationBadge';
-import ProjectBadge from 'sentry/components/idBadge/projectBadge';
+import type {BaseBadgeProps} from 'sentry/components/idBadge/baseBadge';
+import MemberBadge, {MemberBadgeProps} from 'sentry/components/idBadge/memberBadge';
+import OrganizationBadge, {
+  OrganizationBadgeProps,
+} from 'sentry/components/idBadge/organizationBadge';
+import ProjectBadge, {ProjectBadgeProps} from 'sentry/components/idBadge/projectBadge';
 import {TeamBadge} from 'sentry/components/idBadge/teamBadge';
-import UserBadge from 'sentry/components/idBadge/userBadge';
-import {Member, User} from 'sentry/types';
+import UserBadge, {UserBadgeProps} from 'sentry/components/idBadge/userBadge';
+
+import {TeamBadgeProps} from './teamBadge/badge';
 
-type BaseBadgeProps = React.ComponentProps<typeof BaseBadge>;
 type DisplayName = BaseBadgeProps['displayName'];
 
-interface Props extends Omit<BaseBadgeProps, 'displayName'> {
+interface AddedBaseBadgeProps {
   displayName?: DisplayName;
-  member?: Member;
-  user?: User;
 }
+interface GetOrganizationBadgeProps
+  extends AddedBaseBadgeProps,
+    Omit<BaseBadgeProps, 'displayName' | 'organization'>,
+    OrganizationBadgeProps {}
+
+interface GetMemberBadgeProps
+  extends Omit<BaseBadgeProps, 'displayName' | 'member'>,
+    AddedBaseBadgeProps,
+    MemberBadgeProps {}
+
+interface GetUserBadgeProps
+  extends Omit<BaseBadgeProps, 'displayName' | 'user'>,
+    UserBadgeProps,
+    AddedBaseBadgeProps {}
+
+interface GetTeamBadgeProps
+  extends Omit<BaseBadgeProps, 'displayName' | 'team'>,
+    TeamBadgeProps,
+    AddedBaseBadgeProps {}
+
+interface GetProjectBadgeProps
+  extends Omit<BaseBadgeProps, 'displayName' | 'project'>,
+    ProjectBadgeProps,
+    AddedBaseBadgeProps {}
+
+export type GetBadgeProps =
+  | GetOrganizationBadgeProps
+  | GetTeamBadgeProps
+  | GetProjectBadgeProps
+  | GetUserBadgeProps
+  | GetMemberBadgeProps;
 
-function getBadge({
-  organization,
-  team,
-  project,
-  user,
-  member,
-  ...props
-}: Props): React.ReactElement | null {
-  if (organization) {
-    return <OrganizationBadge organization={organization} {...props} />;
+function getBadge(props): React.ReactElement | null {
+  if (props.organization) {
+    return <OrganizationBadge {...props} />;
   }
-  if (team) {
-    return <TeamBadge team={team} {...props} />;
+  if (props.team) {
+    return <TeamBadge {...props} />;
   }
-  if (project) {
-    return <ProjectBadge project={project} {...props} />;
+  if (props.project) {
+    return <ProjectBadge {...props} />;
   }
-  if (user) {
-    return <UserBadge user={user} {...props} />;
+  if (props.user) {
+    return <UserBadge {...props} />;
   }
-  if (member) {
-    return <MemberBadge member={member} {...props} />;
+  if (props.member) {
+    return <MemberBadge {...props} />;
   }
 
   return null;

+ 2 - 4
static/app/components/idBadge/index.tsx

@@ -2,16 +2,14 @@ import styled from '@emotion/styled';
 
 import ErrorBoundary from 'sentry/components/errorBoundary';
 
-import getBadge from './getBadge';
-
-type Props = React.ComponentProps<typeof getBadge> & Record<string, any>;
+import getBadge, {GetBadgeProps} from './getBadge';
 
 /**
  * Public interface for all "id badges":
  * Organization, project, team, user
  */
 
-const IdBadge = (props: Props) => {
+const IdBadge = (props: GetBadgeProps) => {
   const componentBadge = getBadge(props);
 
   if (!componentBadge) {

+ 2 - 2
static/app/components/idBadge/memberBadge.tsx

@@ -6,7 +6,7 @@ import Link, {LinkProps} from 'sentry/components/links/link';
 import space from 'sentry/styles/space';
 import {AvatarUser, Member} from 'sentry/types';
 
-interface Props {
+export interface MemberBadgeProps {
   member: Member;
   avatarSize?: React.ComponentProps<typeof UserAvatar>['size'];
   className?: string;
@@ -40,7 +40,7 @@ const MemberBadge = ({
   member,
   orgId,
   className,
-}: Props) => {
+}: MemberBadgeProps) => {
   const user = getMemberUser(member);
   const title =
     displayName ||

+ 8 - 3
static/app/components/idBadge/organizationBadge.tsx

@@ -4,15 +4,20 @@ import BaseBadge from 'sentry/components/idBadge/baseBadge';
 type BaseBadgeProps = React.ComponentProps<typeof BaseBadge>;
 type Organization = NonNullable<BaseBadgeProps['organization']>;
 
-type Props = Partial<Omit<BaseBadgeProps, 'project' | 'organization' | 'team'>> & {
+export interface OrganizationBadgeProps
+  extends Partial<Omit<BaseBadgeProps, 'project' | 'organization' | 'team'>> {
   // A full organization is not used, but required to satisfy types with
   // withOrganization()
   organization: Organization;
   // If true, will use default max-width, or specify one as a string
   hideOverflow?: boolean | string;
-};
+}
 
-const OrganizationBadge = ({hideOverflow = true, organization, ...props}: Props) => (
+const OrganizationBadge = ({
+  hideOverflow = true,
+  organization,
+  ...props
+}: OrganizationBadgeProps) => (
   <BaseBadge
     displayName={
       <BadgeDisplayName hideOverflow={hideOverflow}>{organization.slug}</BadgeDisplayName>

+ 2 - 2
static/app/components/idBadge/projectBadge.tsx

@@ -10,7 +10,7 @@ import withOrganization from 'sentry/utils/withOrganization';
 type BaseBadgeProps = React.ComponentProps<typeof BaseBadge>;
 type Project = NonNullable<BaseBadgeProps['project']>;
 
-interface Props
+export interface ProjectBadgeProps
   extends Partial<Omit<BaseBadgeProps, 'project' | 'organization' | 'team'>> {
   project: Project;
   className?: string;
@@ -37,7 +37,7 @@ const ProjectBadge = ({
   disableLink = false,
   className,
   ...props
-}: Props) => {
+}: ProjectBadgeProps) => {
   const {slug, id} = project;
 
   const badge = (

+ 6 - 2
static/app/components/idBadge/teamBadge/badge.tsx

@@ -4,14 +4,18 @@ import BaseBadge from 'sentry/components/idBadge/baseBadge';
 type BaseBadgeProps = React.ComponentProps<typeof BaseBadge>;
 type Team = NonNullable<BaseBadgeProps['team']>;
 
-export interface BadgeProps
+export interface TeamBadgeProps
   extends Partial<Omit<BaseBadgeProps, 'project' | 'organization' | 'team'>> {
   team: Team;
   // If true, will use default max-width, or specify one as a string
   hideOverflow?: boolean | string;
 }
 
-const Badge = ({hideOverflow = true, team, ...props}: BadgeProps): React.ReactElement => (
+const Badge = ({
+  hideOverflow = true,
+  team,
+  ...props
+}: TeamBadgeProps): React.ReactElement => (
   <BaseBadge
     displayName={
       <BadgeDisplayName hideOverflow={hideOverflow}>{`#${team.slug}`}</BadgeDisplayName>

+ 2 - 2
static/app/components/idBadge/teamBadge/index.tsx

@@ -1,9 +1,9 @@
 import TeamStore from 'sentry/stores/teamStore';
 import {useLegacyStore} from 'sentry/stores/useLegacyStore';
 
-import Badge, {BadgeProps} from './badge';
+import Badge, {TeamBadgeProps} from './badge';
 
-function TeamBadge(props: BadgeProps) {
+function TeamBadge(props: TeamBadgeProps) {
   const {teams} = useLegacyStore(TeamStore);
 
   // Get the most up-to-date team from the store

+ 3 - 3
static/app/components/idBadge/userBadge.tsx

@@ -4,14 +4,14 @@ import UserAvatar from 'sentry/components/avatar/userAvatar';
 import space from 'sentry/styles/space';
 import {AvatarUser} from 'sentry/types';
 
-type Props = {
+export interface UserBadgeProps {
   avatarSize?: React.ComponentProps<typeof UserAvatar>['size'];
   className?: string;
   displayEmail?: React.ReactNode | string;
   displayName?: React.ReactNode;
   hideEmail?: boolean;
   user?: AvatarUser;
-};
+}
 
 const UserBadge = ({
   avatarSize = 24,
@@ -20,7 +20,7 @@ const UserBadge = ({
   displayEmail,
   user,
   className,
-}: Props) => {
+}: UserBadgeProps) => {
   const title =
     displayName ||
     (user &&