import {css} from '@emotion/react'; import styled from '@emotion/styled'; import debounce from 'lodash/debounce'; import {openCreateTeamModal} from 'sentry/actionCreators/modal'; import {hasEveryAccess} from 'sentry/components/acl/access'; import DropdownAutoComplete from 'sentry/components/dropdownAutoComplete'; import type {Item} from 'sentry/components/dropdownAutoComplete/types'; import DropdownButton from 'sentry/components/dropdownButton'; import {TeamBadge} from 'sentry/components/idBadge/teamBadge'; import Link from 'sentry/components/links/link'; import {Tooltip} from 'sentry/components/tooltip'; import {DEFAULT_DEBOUNCE_DURATION} from 'sentry/constants'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import type {Organization, Project, Team} from 'sentry/types'; import {getButtonHelpText} from 'sentry/views/settings/organizationTeams/utils'; export type TeamSelectProps = { /** * Should button be disabled */ disabled: boolean; /** * callback when teams are added */ onAddTeam: (teamSlug: string) => void; /** * Callback when teams are removed */ onRemoveTeam: (teamSlug: string) => void; organization: Organization; /** * Used to determine whether we should show a loading state while waiting for teams */ loadingTeams?: boolean; /** * Callback when teams are created */ onCreateTeam?: (team: Team) => void; }; export function DropdownAddTeam({ disabled, isLoadingTeams, isAddingTeamToMember = false, isAddingTeamToProject = false, onSearch, onSelect, onCreateTeam, organization, selectedTeams, teams, project, }: { disabled: boolean; isLoadingTeams: boolean; onSearch: (teamSlug: string) => void; onSelect: (teamSlug: string) => void; organization: Organization; selectedTeams: string[]; teams: Team[]; canCreateTeam?: boolean; isAddingTeamToMember?: boolean; isAddingTeamToProject?: boolean; onCreateTeam?: (team: Team) => void; project?: Project; }) { const dropdownItems = teams .filter(team => !selectedTeams.some(slug => slug === team.slug)) .map((team, index) => renderDropdownOption({ isAddingTeamToMember, isAddingTeamToProject, organization, team, index, disabled, }) ); const onDropdownChange = debounce<(e: React.ChangeEvent) => void>( e => onSearch(e.target.value), DEFAULT_DEBOUNCE_DURATION ); return ( onSelect(option.value)} emptyMessage={t('No teams')} menuHeader={renderDropdownHeader({ organization, project, onCreateTeam, })} disabled={disabled} alignMenu="right" > {({isOpen}) => ( {t('Add Team')} )} ); } function renderDropdownOption({ disabled, index, isAddingTeamToMember, organization, team, }: { disabled: boolean; index: number; isAddingTeamToMember: boolean; isAddingTeamToProject: boolean; organization: Organization; team: Team; }) { const hasOrgAdmin = organization.access.includes('org:admin'); const isIdpProvisioned = isAddingTeamToMember && team.flags['idp:provisioned']; const isPermissionGroup = isAddingTeamToMember && !!team.orgRole && !hasOrgAdmin; const buttonHelpText = getButtonHelpText(isIdpProvisioned, isPermissionGroup); return { index, value: team.slug, searchKey: team.slug, label: () => { if (isIdpProvisioned || isPermissionGroup) { return ( ); } return ; }, disabled: disabled || isIdpProvisioned || isPermissionGroup, }; } function renderDropdownHeader({ organization, project, onCreateTeam, }: { organization: Organization; onCreateTeam?: (team) => void; project?: Project; }) { const canCreateTeam = hasEveryAccess(['org:write'], {organization, project}); return ( {t('Teams')} { e.stopPropagation(); e.preventDefault(); openCreateTeamModal({ organization, project, onClose: onCreateTeam, }); }} > {t('Create Team')} ); } const DropdownTeamBadge = styled(TeamBadge)` font-weight: normal; font-size: ${p => p.theme.fontSizeMedium}; text-transform: none; `; const DropdownTeamBadgeDisabled = styled(TeamBadge)` font-weight: normal; font-size: ${p => p.theme.fontSizeMedium}; text-transform: none; filter: grayscale(1); `; const StyledTeamsLabel = styled('div')` display: flex; flex-direction: row; justify-content: space-between; font-size: 0.875em; padding: ${space(0.5)} 0px; text-transform: uppercase; `; const StyledCreateTeamLink = styled(Link)` float: right; text-transform: none; ${p => p.disabled && css` cursor: not-allowed; color: ${p.theme.gray300}; opacity: 0.6; `}; `;