Skip to content

Commit

Permalink
feat(graph): show errors from task graph generation (#14924)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipjfulcher committed Feb 10, 2023
1 parent 5ac46c4 commit 0e3d9cd
Show file tree
Hide file tree
Showing 13 changed files with 235 additions and 69 deletions.
10 changes: 10 additions & 0 deletions graph/client/src/app/feature-tasks/task-graph-error-tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const TaskGraphErrorTooltip = ({ error }: { error: string }) => {
return (
<>
<h2 className="border-b border-solid border-slate-200/10 text-lg font-light text-slate-400 dark:text-slate-500">
There was a problem calculating the task graph for this task
</h2>
<p>{error}</p>
</>
);
};
9 changes: 8 additions & 1 deletion graph/client/src/app/feature-tasks/task-list.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const args: Partial<TaskListProps> = {
defaultConfiguration: 'production',
},
},
files: [],
},
},
{
Expand All @@ -38,6 +39,7 @@ const args: Partial<TaskListProps> = {
data: {
root: 'apps/nested/app',
targets: { build: { configurations: { production: {} } } },
files: [],
},
},
{
Expand All @@ -46,6 +48,7 @@ const args: Partial<TaskListProps> = {
data: {
root: 'apps/app1-e2e',
targets: { e2e: { configurations: { production: {} } } },
files: [],
},
},
{
Expand All @@ -54,6 +57,7 @@ const args: Partial<TaskListProps> = {
data: {
root: 'libs/lib1',
targets: { lint: { configurations: { production: {} } } },
files: [],
},
},
],
Expand All @@ -62,6 +66,9 @@ const args: Partial<TaskListProps> = {
appsDir: 'apps',
libsDir: 'libs',
},
selectedTask: 'app1:build:production',
selectedTarget: 'build',
errors: {
'app1:build': 'Missing executor',
},
};
Primary.args = args;
65 changes: 57 additions & 8 deletions graph/client/src/app/feature-tasks/task-list.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
// nx-ignore-next-line
import type { ProjectGraphNode } from '@nrwl/devkit';
import { getProjectsByType, groupProjectsByDirectory } from '../util';
import {
createTaskName,
getProjectsByType,
groupProjectsByDirectory,
} from '../util';
import { WorkspaceLayout } from '../interfaces';
import { EyeIcon } from '@heroicons/react/24/outline';
import { ExclamationCircleIcon, EyeIcon } from '@heroicons/react/24/outline';
import { ReactNode } from 'react';
import { Tooltip } from '@nrwl/graph/ui-tooltips';
import { TaskGraphErrorTooltip } from './task-graph-error-tooltip';
import { ExperimentalFeature } from '../ui-components/experimental-feature';

interface SidebarProject {
projectGraphNode: ProjectGraphNode;
isSelected: boolean;
error: string | null;
}

function ProjectListItem({
Expand All @@ -25,11 +33,31 @@ function ProjectListItem({
data-project={project.projectGraphNode.name}
title={project.projectGraphNode.name}
data-active={project.isSelected.toString()}
onClick={() => toggleTask(project.projectGraphNode.name)}
onClick={() =>
!project.error ? toggleTask(project.projectGraphNode.name) : null
}
>
{project.projectGraphNode.name}
</label>
</div>

<ExperimentalFeature>
{project.error ? (
<Tooltip
content={<TaskGraphErrorTooltip error={project.error} />}
openAction="click"
floatingPortal={true}
>
<span className="absolute inset-y-0 right-0 flex cursor-pointer items-center text-blue-500 dark:text-sky-500">
<ExclamationCircleIcon
className="h-5 w-5 text-yellow-500 dark:text-yellow-400"
aria-hidden="true"
/>
</span>
</Tooltip>
) : null}
</ExperimentalFeature>

{project.isSelected ? (
<span
title="This task is visible"
Expand Down Expand Up @@ -81,11 +109,16 @@ function SubProjectList({

function mapToSidebarProjectWithTasks(
project: ProjectGraphNode,
selectedProjects: string[]
selectedProjects: string[],
selectedTarget: string,
errors: Record<string, string>
): SidebarProject {
const taskId = createTaskName(project.name, selectedTarget);

return {
projectGraphNode: project,
isSelected: selectedProjects.includes(project.name),
error: errors?.[taskId] ?? null,
};
}

Expand All @@ -96,6 +129,7 @@ export interface TaskListProps {
selectedProjects: string[];
toggleProject: (projectName: string) => void;
children: ReactNode | ReactNode[];
errors: Record<string, string>;
}

export function TaskList({
Expand All @@ -105,13 +139,13 @@ export function TaskList({
selectedProjects,
toggleProject,
children,
errors,
}: TaskListProps) {
const filteredProjects = projects
.filter((project) =>
(project.data as any).targets.hasOwnProperty(selectedTarget)
)
.sort((a, b) => a.name.localeCompare(b.name));

const appProjects = getProjectsByType('app', filteredProjects);
const libProjects = getProjectsByType('lib', filteredProjects);
const e2eProjects = getProjectsByType('e2e', filteredProjects);
Expand Down Expand Up @@ -146,7 +180,12 @@ export function TaskList({
key={'app-' + directoryName}
headerText={directoryName}
projects={appDirectoryGroups[directoryName].map((project) =>
mapToSidebarProjectWithTasks(project, selectedProjects)
mapToSidebarProjectWithTasks(
project,
selectedProjects,
selectedTarget,
errors
)
)}
toggleTask={toggleProject}
></SubProjectList>
Expand All @@ -163,7 +202,12 @@ export function TaskList({
key={'e2e-' + directoryName}
headerText={directoryName}
projects={e2eDirectoryGroups[directoryName].map((project) =>
mapToSidebarProjectWithTasks(project, selectedProjects)
mapToSidebarProjectWithTasks(
project,
selectedProjects,
selectedTarget,
errors
)
)}
toggleTask={toggleProject}
></SubProjectList>
Expand All @@ -180,7 +224,12 @@ export function TaskList({
key={'lib-' + directoryName}
headerText={directoryName}
projects={libDirectoryGroups[directoryName].map((project) =>
mapToSidebarProjectWithTasks(project, selectedProjects)
mapToSidebarProjectWithTasks(
project,
selectedProjects,
selectedTarget,
errors
)
)}
toggleTask={toggleProject}
></SubProjectList>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useRouteError } from 'react-router-dom';

export function TasksSidebarErrorBoundary() {
let error = useRouteError();
console.error(error);
return (
<div className="mt-8 px-4">
<h2 className="mt-8 border-b border-solid border-slate-200/10 text-lg font-light text-slate-400 dark:text-slate-500">
Error
</h2>
<p>There was a problem loading your task graph.</p>
</div>
);
}
20 changes: 5 additions & 15 deletions graph/client/src/app/feature-tasks/tasks-sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,7 @@ import { CheckboxPanel } from '../ui-components/checkbox-panel';
import { Dropdown } from '@nrwl/graph/ui-components';
import { ShowHideAll } from '../ui-components/show-hide-all';
import { useCurrentPath } from '../hooks/use-current-path';
import { useRouteConstructor } from '../util';

function createTaskName(
project: string,
target: string,
configuration?: string
) {
if (configuration) {
return `${project}:${target}:${configuration}`;
} else {
return `${project}:${target}`;
}
}
import { createTaskName, useRouteConstructor } from '../util';

export function TasksSidebar() {
const graphService = getGraphService();
Expand All @@ -47,8 +35,9 @@ export function TasksSidebar() {
const routeData = useRouteLoaderData(
'selectedTarget'
) as TaskGraphClientResponse;
const { taskGraphs } = routeData;
const { projects, targets } = selectedWorkspaceRouteData;
const { taskGraphs, errors } = routeData;
let { projects, targets } = selectedWorkspaceRouteData;

const selectedTarget = params['selectedTarget'] ?? targets[0];

const [selectedProjects, setSelectedProjects] = useState<string[]>([]);
Expand Down Expand Up @@ -217,6 +206,7 @@ export function TasksSidebar() {
workspaceLayout={workspaceLayout}
selectedTarget={selectedTarget}
toggleProject={toggleProject}
errors={errors}
>
<label
htmlFor="selectedTarget"
Expand Down
5 changes: 4 additions & 1 deletion graph/client/src/app/mock-project-graph-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,10 @@ export class MockProjectGraphService implements ProjectGraphService {
groupByFolder: false,
};

private taskGraphsResponse: TaskGraphClientResponse = { taskGraphs: {} };
private taskGraphsResponse: TaskGraphClientResponse = {
taskGraphs: {},
errors: {},
};

constructor(updateFrequency: number = 5000) {
setInterval(() => this.updateResponse(), updateFrequency);
Expand Down
2 changes: 2 additions & 0 deletions graph/client/src/app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { getEnvironmentConfig } from './hooks/use-environment-config';
import { ProjectGraphClientResponse } from 'nx/src/command-line/dep-graph';
import { getProjectGraphDataService } from './hooks/get-project-graph-data-service';
import { getProjectGraphService } from './machines/get-services';
import { TasksSidebarErrorBoundary } from './feature-tasks/tasks-sidebar-error-boundary';

const { appConfig } = getEnvironmentConfig();
const projectGraphDataService = getProjectGraphDataService();
Expand Down Expand Up @@ -88,6 +89,7 @@ const childRoutes: RouteObject[] = [
},
path: 'tasks',
id: 'selectedTarget',
errorElement: <TasksSidebarErrorBoundary />,
shouldRevalidate: ({ currentParams, nextParams }) => {
return (
!currentParams.selectedWorkspaceId ||
Expand Down
12 changes: 12 additions & 0 deletions graph/client/src/app/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,15 @@ export function groupProjectsByDirectory(

return groups;
}

export function createTaskName(
project: string,
target: string,
configuration?: string
) {
if (configuration) {
return `${project}:${target}:${configuration}`;
} else {
return `${project}:${target}`;
}
}
2 changes: 1 addition & 1 deletion graph/ui-components/src/lib/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export function Dropdown(props: DropdownProps) {
const { className, children, ...rest } = props;
return (
<select
className={`flex w-auto items-center rounded-md rounded-md border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700 ${className}`}
className={`flex items-center rounded-md rounded-md border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700 ${className}`}
{...rest}
>
{children}
Expand Down
Loading

1 comment on commit 0e3d9cd

@vercel
Copy link

@vercel vercel bot commented on 0e3d9cd Feb 10, 2023

Choose a reason for hiding this comment

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

Successfully deployed to the following URLs:

nx-dev – ./

nx-dev-nrwl.vercel.app
nx-five.vercel.app
nx.dev
nx-dev-git-master-nrwl.vercel.app

Please sign in to comment.