Browse Source

feat(workflow): Add team selector to projects page (#33396)

* feat(workflow): Add team selector to projects page

Add team selector to the projects page.

FIXES WOR-1757

* add redesign check and update test
Kelly Carino 2 years ago
parent
commit
6c0546a0f3

+ 76 - 3
static/app/views/projectsDashboard/index.tsx

@@ -1,6 +1,7 @@
-import {Fragment, useEffect} from 'react';
+import {Fragment, useEffect, useState} from 'react';
 import LazyLoad from 'react-lazyload';
 import {RouteComponentProps} from 'react-router';
+import {useTheme} from '@emotion/react';
 import styled from '@emotion/styled';
 import {withProfiler} from '@sentry/react';
 import flatten from 'lodash/flatten';
@@ -8,6 +9,7 @@ import uniqBy from 'lodash/uniqBy';
 
 import {Client} from 'sentry/api';
 import Button from 'sentry/components/button';
+import TeamSelector from 'sentry/components/forms/teamSelector';
 import IdBadge from 'sentry/components/idBadge';
 import Link from 'sentry/components/links/link';
 import LoadingError from 'sentry/components/loadingError';
@@ -21,6 +23,7 @@ import ProjectsStatsStore from 'sentry/stores/projectsStatsStore';
 import space from 'sentry/styles/space';
 import {Organization, TeamWithProjects} from 'sentry/types';
 import {sortProjects} from 'sentry/utils';
+import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser';
 import withApi from 'sentry/utils/withApi';
 import withOrganization from 'sentry/utils/withOrganization';
 import withTeamsForUser from 'sentry/utils/withTeamsForUser';
@@ -43,6 +46,7 @@ function Dashboard({teams, params, organization, loadingTeams, error}: Props) {
       ProjectsStatsStore.reset();
     };
   }, []);
+  const [currentTeam, setCurrentTeam] = useState<string>();
 
   if (loadingTeams) {
     return <LoadingIndicator />;
@@ -52,10 +56,14 @@ function Dashboard({teams, params, organization, loadingTeams, error}: Props) {
     return <LoadingError message={t('An error occurred while fetching your projects')} />;
   }
 
+  const theme = useTheme();
+  const isSuperuser = isActiveSuperuser();
+
   const filteredTeams = teams.filter(team => team.projects.length);
   filteredTeams.sort((team1, team2) => team1.slug.localeCompare(team2.slug));
 
   const projects = uniqBy(flatten(teams.map(teamObj => teamObj.projects)), 'id');
+  const currentProjects = filteredTeams.find(team => team.id === currentTeam)?.projects;
   const favorites = projects.filter(project => project.isBookmarked);
 
   const canCreateProjects = organization.access.includes('project:admin');
@@ -67,6 +75,11 @@ function Dashboard({teams, params, organization, loadingTeams, error}: Props) {
   const showEmptyMessage = projects.length === 0 && favorites.length === 0;
   const showResources = projects.length === 1 && !projects[0].firstEvent;
 
+  function handleChange(newValue) {
+    const updatedTeam = newValue ? newValue.actor.id : '';
+    setCurrentTeam(updatedTeam);
+  }
+
   if (showEmptyMessage) {
     return (
       <NoProjectMessage organization={organization} superuserNeedsToBeProjectMember />
@@ -114,6 +127,60 @@ function Dashboard({teams, params, organization, loadingTeams, error}: Props) {
               </Button>
             </ButtonContainer>
           </ProjectsHeader>
+          {hasProjectRedesign && (
+            <StyledTeamSelector
+              name="select-team"
+              aria-label="select-team"
+              inFieldLabel={t('Team: ')}
+              placeholder={t('My Teams')}
+              value={currentTeam}
+              onChange={choice => handleChange(choice)}
+              teamFilter={isSuperuser ? undefined : filterTeam => filterTeam.isMember}
+              useId
+              clearable
+              styles={{
+                placeholder: (provided: any) => ({
+                  ...provided,
+                  paddingLeft: space(0.5),
+                  ':before': {
+                    ...provided[':before'],
+                    color: theme.textColor,
+                  },
+                }),
+                singleValue(provided: any) {
+                  const custom = {
+                    display: 'flex',
+                    justifyContent: 'space-between',
+                    alignItems: 'center',
+                    fontSize: theme.fontSizeMedium,
+                    ':before': {
+                      ...provided[':before'],
+                      color: theme.textColor,
+                      marginRight: space(1.5),
+                      marginLeft: space(0.5),
+                    },
+                  };
+                  return {...provided, ...custom};
+                },
+                input: (provided: any, state: any) => ({
+                  ...provided,
+                  display: 'grid',
+                  gridTemplateColumns: 'max-content 1fr',
+                  alignItems: 'center',
+                  marginRight: space(0.25),
+                  gridGap: space(1.5),
+                  ':before': {
+                    backgroundColor: state.theme.backgroundSecondary,
+                    height: 24,
+                    width: 38,
+                    borderRadius: 3,
+                    content: '""',
+                    display: 'block',
+                  },
+                }),
+              }}
+            />
+          )}
         </Fragment>
       )}
 
@@ -121,7 +188,7 @@ function Dashboard({teams, params, organization, loadingTeams, error}: Props) {
         <LazyLoad once debounce={50} height={300} offset={300}>
           <ProjectCardsContainer>
             <ProjectCards>
-              {projects.map(project => (
+              {(currentProjects ?? projects).map(project => (
                 <ProjectCard
                   data-test-id={project.slug}
                   key={project.slug}
@@ -182,8 +249,14 @@ const ButtonContainer = styled('div')`
   gap: ${space(1)};
 `;
 
+const StyledTeamSelector = styled(TeamSelector)`
+  margin: ${space(2)} 30px 0 0;
+  width: 300px;
+  margin-left: auto;
+`;
+
 const ProjectCardsContainer = styled('div')`
-  padding: 20px 30px 0 30px;
+  padding: ${space(2)} 30px ${space(2)} 30px;
 `;
 
 const ProjectCards = styled('div')`

+ 1 - 0
tests/js/spec/views/projectsDashboard/index.spec.jsx

@@ -144,6 +144,7 @@ describe('ProjectsDashboard', function () {
 
       expect(screen.getByTestId('join-team')).toBeInTheDocument();
       expect(screen.getByTestId('create-project')).toBeInTheDocument();
+      expect(screen.getByText('My Teams')).toBeInTheDocument();
       expect(screen.queryByTestId('team')).not.toBeInTheDocument();
       expect(screen.queryByText('Resources')).not.toBeInTheDocument();
     });