mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-10-30 14:49:14 +00:00
169 lines
5.0 KiB
TypeScript
169 lines
5.0 KiB
TypeScript
import {useState} from 'react';
|
|
import type {RouteComponentProps} from 'react-router';
|
|
import styled from '@emotion/styled';
|
|
import debounce from 'lodash/debounce';
|
|
import partition from 'lodash/partition';
|
|
|
|
import {openCreateTeamModal} from 'sentry/actionCreators/modal';
|
|
import {Button} from 'sentry/components/button';
|
|
import LoadingIndicator from 'sentry/components/loadingIndicator';
|
|
import Panel from 'sentry/components/panels/panel';
|
|
import PanelBody from 'sentry/components/panels/panelBody';
|
|
import PanelHeader from 'sentry/components/panels/panelHeader';
|
|
import SearchBar from 'sentry/components/searchBar';
|
|
import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
|
|
import {TeamRoleColumnLabel} from 'sentry/components/teamRoleUtils';
|
|
import {DEFAULT_DEBOUNCE_DURATION} from 'sentry/constants';
|
|
import {IconAdd} from 'sentry/icons';
|
|
import {t} from 'sentry/locale';
|
|
import {space} from 'sentry/styles/space';
|
|
import type {AccessRequest, Organization} from 'sentry/types';
|
|
import {useTeams} from 'sentry/utils/useTeams';
|
|
import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
|
|
import {RoleOverwritePanelAlert} from 'sentry/views/settings/organizationTeams/roleOverwriteWarning';
|
|
|
|
import AllTeamsList from './allTeamsList';
|
|
import {GRID_TEMPLATE} from './allTeamsRow';
|
|
import OrganizationAccessRequests from './organizationAccessRequests';
|
|
|
|
type Props = {
|
|
access: Set<string>;
|
|
features: Set<string>;
|
|
onRemoveAccessRequest: (id: string, isApproved: boolean) => void;
|
|
organization: Organization;
|
|
requestList: AccessRequest[];
|
|
} & RouteComponentProps<{}, {}>;
|
|
|
|
function OrganizationTeams({
|
|
organization,
|
|
access,
|
|
features,
|
|
requestList,
|
|
onRemoveAccessRequest,
|
|
}: Props) {
|
|
const [teamQuery, setTeamQuery] = useState('');
|
|
const {initiallyLoaded} = useTeams({provideUserTeams: true});
|
|
const {teams, onSearch, loadMore, hasMore, fetching} = useTeams();
|
|
|
|
if (!organization) {
|
|
return null;
|
|
}
|
|
const canCreateTeams = access.has('project:admin');
|
|
|
|
const action = (
|
|
<Button
|
|
priority="primary"
|
|
size="sm"
|
|
disabled={!canCreateTeams}
|
|
title={
|
|
!canCreateTeams ? t('You do not have permission to create teams') : undefined
|
|
}
|
|
onClick={() =>
|
|
openCreateTeamModal({
|
|
organization,
|
|
})
|
|
}
|
|
icon={<IconAdd isCircled />}
|
|
>
|
|
{t('Create Team')}
|
|
</Button>
|
|
);
|
|
|
|
const title = t('Teams');
|
|
|
|
const debouncedSearch = debounce(onSearch, DEFAULT_DEBOUNCE_DURATION);
|
|
function handleSearch(query: string) {
|
|
setTeamQuery(query);
|
|
debouncedSearch(query);
|
|
}
|
|
|
|
const {slug: orgSlug, orgRole, orgRoleList, teamRoleList} = organization;
|
|
const filteredTeams = teams.filter(team =>
|
|
`#${team.slug}`.toLowerCase().includes(teamQuery.toLowerCase())
|
|
);
|
|
const [userTeams, otherTeams] = partition(filteredTeams, team => team.isMember);
|
|
|
|
return (
|
|
<div data-test-id="team-list">
|
|
<SentryDocumentTitle title={title} orgSlug={orgSlug} />
|
|
<SettingsPageHeader title={title} action={action} />
|
|
|
|
<OrganizationAccessRequests
|
|
orgSlug={organization.slug}
|
|
requestList={requestList}
|
|
onRemoveAccessRequest={onRemoveAccessRequest}
|
|
/>
|
|
<StyledSearchBar
|
|
placeholder={t('Search teams')}
|
|
onChange={handleSearch}
|
|
query={teamQuery}
|
|
/>
|
|
<Panel>
|
|
<StyledPanelHeader>
|
|
<div>{t('Your Teams')}</div>
|
|
<div />
|
|
<div>
|
|
<TeamRoleColumnLabel />
|
|
</div>
|
|
<div />
|
|
</StyledPanelHeader>
|
|
<PanelBody>
|
|
<RoleOverwritePanelAlert
|
|
orgRole={orgRole}
|
|
orgRoleList={orgRoleList}
|
|
teamRoleList={teamRoleList}
|
|
isSelf
|
|
/>
|
|
{initiallyLoaded ? (
|
|
<AllTeamsList
|
|
organization={organization}
|
|
teamList={userTeams.filter(team => team.slug.includes(teamQuery))}
|
|
access={access}
|
|
openMembership={false}
|
|
/>
|
|
) : (
|
|
<LoadingIndicator />
|
|
)}
|
|
</PanelBody>
|
|
</Panel>
|
|
<Panel>
|
|
<PanelHeader>{t('Other Teams')}</PanelHeader>
|
|
<PanelBody>
|
|
<AllTeamsList
|
|
organization={organization}
|
|
teamList={otherTeams}
|
|
access={access}
|
|
openMembership={
|
|
!!(features.has('open-membership') || access.has('org:write'))
|
|
}
|
|
/>
|
|
</PanelBody>
|
|
</Panel>
|
|
{hasMore && (
|
|
<LoadMoreWrapper>
|
|
{fetching && <LoadingIndicator mini />}
|
|
<Button onClick={() => loadMore(teamQuery)}>{t('Show more')}</Button>
|
|
</LoadMoreWrapper>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
const StyledSearchBar = styled(SearchBar)`
|
|
margin-bottom: ${space(2)};
|
|
`;
|
|
|
|
const StyledPanelHeader = styled(PanelHeader)`
|
|
${GRID_TEMPLATE}
|
|
`;
|
|
|
|
const LoadMoreWrapper = styled('div')`
|
|
display: grid;
|
|
gap: ${space(2)};
|
|
align-items: center;
|
|
justify-content: end;
|
|
grid-auto-flow: column;
|
|
`;
|
|
|
|
export default OrganizationTeams;
|