import type { ProjectGraphNode } from '@nrwl/devkit'; import { useDepGraphService } from '../hooks/use-dep-graph'; import { useDepGraphSelector } from '../hooks/use-dep-graph-selector'; import { allProjectsSelector, selectedProjectNamesSelector, workspaceLayoutSelector, } from '../machines/selectors'; import { parseParentDirectoriesFromPilePath } from '../util'; function getProjectsByType(type: string, projects: ProjectGraphNode[]) { return projects .filter((project) => project.type === type) .sort((a, b) => a.name.localeCompare(b.name)); } interface SidebarProject { projectGraphNode: ProjectGraphNode; isSelected: boolean; } type DirectoryProjectRecord = Record; function groupProjectsByDirectory( projects: ProjectGraphNode[], selectedProjects: string[], workspaceLayout: { appsDir: string; libsDir: string } ): DirectoryProjectRecord { let groups = {}; projects.forEach((project) => { const workspaceRoot = project.type === 'app' || project.type === 'e2e' ? workspaceLayout.appsDir : workspaceLayout.libsDir; const directories = parseParentDirectoriesFromPilePath( project.data.root, workspaceRoot ); const directory = directories.join('/'); if (!groups.hasOwnProperty(directory)) { groups[directory] = []; } groups[directory].push({ projectGraphNode: project, isSelected: selectedProjects.includes(project.name), }); }); return groups; } function ProjectListItem({ project, toggleProject, focusProject, }: { project: SidebarProject; toggleProject: (projectId: string, currentlySelected: boolean) => void; focusProject: (projectId: string) => void; }) { return (
  • {project.isSelected ? ( toggleProject(project.projectGraphNode.name, project.isSelected) } > ) : null}
  • ); } function SubProjectList({ headerText, projects, selectProject, deselectProject, focusProject, }: { headerText: string; projects: SidebarProject[]; selectProject: (projectName: string) => void; deselectProject: (projectName: string) => void; focusProject: (projectName: string) => void; }) { let sortedProjects = [...projects]; sortedProjects.sort((a, b) => { return a.projectGraphNode.name.localeCompare(b.projectGraphNode.name); }); function toggleProject(projectName: string, currentlySelected: boolean) { if (currentlySelected) { deselectProject(projectName); } else { selectProject(projectName); } } return ( <>

    {headerText}

    ); } export function ProjectList() { const depGraphService = useDepGraphService(); function deselectProject(projectName: string) { depGraphService.send({ type: 'deselectProject', projectName }); } function selectProject(projectName: string) { depGraphService.send({ type: 'selectProject', projectName }); } function focusProject(projectName: string) { depGraphService.send({ type: 'focusProject', projectName }); } const projects = useDepGraphSelector(allProjectsSelector); const workspaceLayout = useDepGraphSelector(workspaceLayoutSelector); const selectedProjects = useDepGraphSelector(selectedProjectNamesSelector); const appProjects = getProjectsByType('app', projects); const libProjects = getProjectsByType('lib', projects); const e2eProjects = getProjectsByType('e2e', projects); const appDirectoryGroups = groupProjectsByDirectory( appProjects, selectedProjects, workspaceLayout ); const libDirectoryGroups = groupProjectsByDirectory( libProjects, selectedProjects, workspaceLayout ); const e2eDirectoryGroups = groupProjectsByDirectory( e2eProjects, selectedProjects, workspaceLayout ); const sortedAppDirectories = Object.keys(appDirectoryGroups).sort(); const sortedLibDirectories = Object.keys(libDirectoryGroups).sort(); const sortedE2EDirectories = Object.keys(e2eDirectoryGroups).sort(); return (

    app projects

    {sortedAppDirectories.map((directoryName) => { return ( ); })}

    e2e projects

    {sortedE2EDirectories.map((directoryName) => { return ( ); })}

    lib projects

    {sortedLibDirectories.map((directoryName) => { return ( ); })}
    ); } export default ProjectList;