ownershipOwnerFilter.tsx 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. import {Fragment, useMemo} from 'react';
  2. import styled from '@emotion/styled';
  3. import ActorAvatar from 'sentry/components/avatar/actorAvatar';
  4. import Badge from 'sentry/components/badge';
  5. import {CompactSelect} from 'sentry/components/compactSelect';
  6. import {IconUser} from 'sentry/icons';
  7. import {t} from 'sentry/locale';
  8. import type {Actor} from 'sentry/types';
  9. interface Props {
  10. actors: Actor[];
  11. handleChangeFilter: (activeFilters: string[]) => void;
  12. isMyTeams: boolean;
  13. selectedTeams: string[];
  14. }
  15. export function OwnershipOwnerFilter({
  16. selectedTeams,
  17. handleChangeFilter,
  18. actors,
  19. isMyTeams,
  20. }: Props) {
  21. const actorOptions = useMemo(
  22. () =>
  23. actors.map(actor => ({
  24. value: `${actor.type}:${actor.id}`,
  25. label: actor.type === 'team' ? `#${actor.name}` : actor.name,
  26. leadingItems: <ActorAvatar actor={actor} size={18} />,
  27. })),
  28. [actors]
  29. );
  30. const label = useMemo(() => {
  31. if (isMyTeams) {
  32. return t('My Teams');
  33. }
  34. if (selectedTeams.length === 0) {
  35. return t('Everyone');
  36. }
  37. const firstActor = selectedTeams[0];
  38. const actor = actors.find(({type, id}) => `${type}:${id}` === firstActor);
  39. if (!actor) {
  40. return t('Unknown');
  41. }
  42. return actor.type === 'team' ? `#${actor.name}` : actor.name;
  43. }, [selectedTeams, actors, isMyTeams]);
  44. return (
  45. <CompactSelect
  46. multiple
  47. clearable
  48. searchable
  49. menuTitle={t('Filter owners')}
  50. options={actorOptions}
  51. value={selectedTeams}
  52. onChange={opts => {
  53. // Compact select type inference does not work - onChange type is actually T | null.
  54. if (!opts) {
  55. return handleChangeFilter([]);
  56. }
  57. return handleChangeFilter(opts.map(opt => opt.value));
  58. }}
  59. triggerLabel={
  60. <Fragment>
  61. {label}
  62. {!isMyTeams && selectedTeams.length > 1 && (
  63. <StyledBadge text={`+${selectedTeams.length - 1}`} />
  64. )}
  65. </Fragment>
  66. }
  67. triggerProps={{icon: <IconUser />}}
  68. />
  69. );
  70. }
  71. const StyledBadge = styled(Badge)`
  72. flex-shrink: 0;
  73. `;