123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- import {Component} from 'react';
- import styled from '@emotion/styled';
- import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
- import {fetchOrganizationDetails} from 'sentry/actionCreators/organizations';
- import {joinTeam, leaveTeam} from 'sentry/actionCreators/teams';
- import TeamActions from 'sentry/actions/teamActions';
- import {Client} from 'sentry/api';
- import Button from 'sentry/components/button';
- import IdBadge from 'sentry/components/idBadge';
- import Link from 'sentry/components/links/link';
- import {PanelItem} from 'sentry/components/panels';
- import {t, tct, tn} from 'sentry/locale';
- import space from 'sentry/styles/space';
- import {Organization, Team} from 'sentry/types';
- import withApi from 'sentry/utils/withApi';
- type Props = {
- api: Client;
- openMembership: boolean;
- organization: Organization;
- team: Team;
- urlPrefix: string;
- };
- type State = {
- error: boolean;
- loading: boolean;
- };
- class AllTeamsRow extends Component<Props, State> {
- state: State = {
- loading: false,
- error: false,
- };
- reloadProjects() {
- const {organization} = this.props;
- // After a change in teams has happened, refresh the project store
- fetchOrganizationDetails(organization.slug, {
- loadProjects: true,
- });
- }
- handleRequestAccess = () => {
- const {team} = this.props;
- try {
- this.joinTeam({
- successMessage: tct('You have requested access to [team]', {
- team: `#${team.slug}`,
- }),
- errorMessage: tct('Unable to request access to [team]', {
- team: `#${team.slug}`,
- }),
- });
- // Update team so that `isPending` is true
- TeamActions.updateSuccess(team.slug, {
- ...team,
- isPending: true,
- });
- } catch (_err) {
- // No need to do anything
- }
- };
- handleJoinTeam = async () => {
- const {team} = this.props;
- await this.joinTeam({
- successMessage: tct('You have joined [team]', {
- team: `#${team.slug}`,
- }),
- errorMessage: tct('Unable to join [team]', {
- team: `#${team.slug}`,
- }),
- });
- this.reloadProjects();
- };
- joinTeam = ({
- successMessage,
- errorMessage,
- }: {
- errorMessage: React.ReactNode;
- successMessage: React.ReactNode;
- }) => {
- const {api, organization, team} = this.props;
- this.setState({
- loading: true,
- });
- return new Promise<void>((resolve, reject) =>
- joinTeam(
- api,
- {
- orgId: organization.slug,
- teamId: team.slug,
- },
- {
- success: () => {
- this.setState({
- loading: false,
- error: false,
- });
- addSuccessMessage(successMessage);
- resolve();
- },
- error: () => {
- this.setState({
- loading: false,
- error: true,
- });
- addErrorMessage(errorMessage);
- reject(new Error('Unable to join team'));
- },
- }
- )
- );
- };
- handleLeaveTeam = () => {
- const {api, organization, team} = this.props;
- this.setState({
- loading: true,
- });
- leaveTeam(
- api,
- {
- orgId: organization.slug,
- teamId: team.slug,
- },
- {
- success: () => {
- this.setState({
- loading: false,
- error: false,
- });
- addSuccessMessage(
- tct('You have left [team]', {
- team: `#${team.slug}`,
- })
- );
- // Reload ProjectsStore
- this.reloadProjects();
- },
- error: () => {
- this.setState({
- loading: false,
- error: true,
- });
- addErrorMessage(
- tct('Unable to leave [team]', {
- team: `#${team.slug}`,
- })
- );
- },
- }
- );
- };
- render() {
- const {team, urlPrefix, openMembership} = this.props;
- const display = (
- <IdBadge
- team={team}
- avatarSize={36}
- description={tn('%s Member', '%s Members', team.memberCount)}
- />
- );
- // You can only view team details if you have access to team -- this should account
- // for your role + org open membership
- const canViewTeam = team.hasAccess;
- return (
- <TeamPanelItem>
- <TeamNameWrapper>
- {canViewTeam ? (
- <TeamLink to={`${urlPrefix}teams/${team.slug}/`}>{display}</TeamLink>
- ) : (
- display
- )}
- </TeamNameWrapper>
- <Spacer>
- {this.state.loading ? (
- <Button size="sm" disabled>
- ...
- </Button>
- ) : team.isMember ? (
- <Button size="sm" onClick={this.handleLeaveTeam}>
- {t('Leave Team')}
- </Button>
- ) : team.isPending ? (
- <Button
- size="sm"
- disabled
- title={t(
- 'Your request to join this team is being reviewed by organization owners'
- )}
- >
- {t('Request Pending')}
- </Button>
- ) : openMembership ? (
- <Button size="sm" onClick={this.handleJoinTeam}>
- {t('Join Team')}
- </Button>
- ) : (
- <Button size="sm" onClick={this.handleRequestAccess}>
- {t('Request Access')}
- </Button>
- )}
- </Spacer>
- </TeamPanelItem>
- );
- }
- }
- const TeamLink = styled(Link)`
- display: inline-block;
- &.focus-visible {
- margin: -${space(1)};
- padding: ${space(1)};
- background: #f2eff5;
- border-radius: 3px;
- outline: none;
- }
- `;
- export {AllTeamsRow};
- export default withApi(AllTeamsRow);
- const TeamPanelItem = styled(PanelItem)`
- padding: 0;
- align-items: center;
- `;
- const Spacer = styled('div')`
- padding: ${space(2)};
- `;
- const TeamNameWrapper = styled(Spacer)`
- flex: 1;
- `;
|