Skip to content

fix(project-dashboard): Show projects without teams #90355

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8 changes: 8 additions & 0 deletions static/app/views/projectsDashboard/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,13 @@ describe('ProjectsDashboard', function () {
firstEvent: new Date().toISOString(),
stats: [],
}),
ProjectFixture({
id: '4',
slug: 'project4',
teams: [],
firstEvent: new Date().toISOString(),
stats: [],
}),
];

ProjectsStore.loadInitialData(projects);
Expand Down Expand Up @@ -392,6 +399,7 @@ describe('ProjectsDashboard', function () {

expect(await screen.findByText('project3')).toBeInTheDocument();
expect(screen.queryByText('project2')).not.toBeInTheDocument();
expect(screen.queryByText('project4')).not.toBeInTheDocument();
});

it('renders projects by search', async function () {
Expand Down
79 changes: 56 additions & 23 deletions static/app/views/projectsDashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,54 @@ function addProjectsToTeams(teams: Team[], projects: Project[]): TeamWithProject
}));
}

function getFilteredProjectsBasedOnTeams({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there's a significant amount of code dedicated to filtering the projects, I extracted it into a new function to make it clearer and more manageable

allTeams,
userTeams,
selectedTeams,
isAllTeams,
showNonMemberProjects,
projects,
projectQuery,
}: {
allTeams: Team[];
isAllTeams: boolean;
projectQuery: string;
projects: Project[];
selectedTeams: string[];
showNonMemberProjects: boolean;
userTeams: Team[];
}): Project[] {
const myTeamIds = new Set(userTeams.map(team => team.id));
const includeMyTeams = isAllTeams || selectedTeams.includes('myteams');
const selectedOtherTeamIds = new Set(
selectedTeams.filter(teamId => teamId !== 'myteams')
);
const myTeams = includeMyTeams ? allTeams.filter(team => myTeamIds.has(team.id)) : [];
const otherTeams = isAllTeams
? allTeams
: allTeams.filter(team => selectedOtherTeamIds.has(String(team.id)));

const visibleTeams = [...myTeams, ...otherTeams].filter(team => {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this contained duplicated entries too

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok this actually have to contain duplicates, otherwise the test "renders correct project with selected team" breaks.

if (showNonMemberProjects) {
return true;
}
return team.isMember;
});
const teamsWithProjects = addProjectsToTeams(visibleTeams, projects);
const currentProjects = uniqBy(
teamsWithProjects.flatMap(team => team.projects),
'id'
);
const currentProjectIds = new Set(currentProjects.map(p => p.id));
const unassignedProjects =
isAllTeams && showNonMemberProjects
? projects.filter(project => !currentProjectIds.has(project.id))
: [];
return [...currentProjects, ...unassignedProjects].filter(project =>
project.slug.includes(projectQuery)
);
}

function Dashboard() {
const navigate = useNavigate();
const location = useLocation();
Expand Down Expand Up @@ -123,33 +171,18 @@ function Dashboard() {
return <LoadingError message={t('An error occurred while fetching your projects')} />;
}

const includeMyTeams = isAllTeams || selectedTeams.includes('myteams');
const hasOtherTeams = selectedTeams.some(team => team !== 'myteams');
const myTeams = includeMyTeams ? userTeams : [];
const otherTeams = isAllTeams
? allTeams
: hasOtherTeams
? allTeams.filter(team => selectedTeams.includes(`${team.id}`))
: [];
const filteredTeams = [...myTeams, ...otherTeams].filter(team => {
if (showNonMemberProjects) {
return true;
}

return team.isMember;
const filteredProjects = getFilteredProjectsBasedOnTeams({
allTeams,
userTeams,
selectedTeams,
isAllTeams,
showNonMemberProjects,
projects,
projectQuery,
});
const filteredTeamsWithProjects = addProjectsToTeams(filteredTeams, projects);

const currentProjects = uniqBy(
filteredTeamsWithProjects.flatMap(team => team.projects),
'id'
);
setGroupedEntityTag('projects.total', 1000, projects.length);

const filteredProjects = currentProjects.filter(project =>
project.slug.includes(projectQuery)
);

const showResources = projects.length === 1 && !projects[0]!.firstEvent;

const canJoinTeam = organization.access.includes('team:read');
Expand Down
Loading