Skip to content

Commit

Permalink
chore(graph): add tasks to graph (#13133)
Browse files Browse the repository at this point in the history
  • Loading branch information
philipjfulcher committed Nov 11, 2022
1 parent a300c0e commit c18ec6c
Show file tree
Hide file tree
Showing 84 changed files with 973 additions and 692 deletions.
3 changes: 2 additions & 1 deletion graph/client-e2e/src/support/app.po.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export const getSelectProjectsMessage = () => cy.get('#no-projects-chosen');
export const getSelectProjectsMessage = () =>
cy.get('[data-cy=no-projects-selected]');
export const getGraph = () => cy.get('#graph-container');
export const getSelectAllButton = () => cy.get('[data-cy=selectAllButton]');
export const getDeselectAllButton = () => cy.get('[data-cy=deselectAllButton]');
Expand Down
9 changes: 2 additions & 7 deletions graph/client/src/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { GlobalStateProvider } from './state.provider';
import { themeInit } from './theme-resolver';
import { rankDirInit } from './rankdir-resolver';
import {
createBrowserRouter,
RouterProvider,
createHashRouter,
RouterProvider,
} from 'react-router-dom';
import { routes } from './routes';
import { getEnvironmentConfig } from './hooks/use-environment-config';
Expand All @@ -22,11 +21,7 @@ if (environmentConfig.localMode === 'build') {
const router = routerCreate(routes);

export function App() {
return (
<GlobalStateProvider>
<RouterProvider router={router} />
</GlobalStateProvider>
);
return <RouterProvider router={router} />;
}

export default App;
13 changes: 13 additions & 0 deletions graph/client/src/app/external-api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getProjectGraphService } from './machines/get-services';

export class ExternalApi {
projectGraphService = getProjectGraphService();

focusProject(projectName: string) {
this.projectGraphService.send({ type: 'focusProject', projectName });
}

enableExperimentalFeatures() {
window.appConfig.showExperimentalFeatures = true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useSelector } from '@xstate/react';
import { ProjectGraphState } from '../machines/interfaces';
import { getProjectGraphService } from '../../machines/get-services';

export type ProjectGraphSelector<T> = (
projectGraphState: ProjectGraphState
) => T;

export function useProjectGraphSelector<T>(
selectorFunc: ProjectGraphSelector<T>
): T {
const projectGraphService = getProjectGraphService();

return useSelector<typeof projectGraphService, T>(
projectGraphService,
selectorFunc
);
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { assign } from '@xstate/immer';
import { actions, send } from 'xstate';
import { DepGraphStateNodeConfig } from './interfaces';
import { ProjectGraphStateNodeConfig } from './interfaces';

export const customSelectedStateConfig: DepGraphStateNodeConfig = {
export const customSelectedStateConfig: ProjectGraphStateNodeConfig = {
entry: actions.choose([
{
cond: 'selectActionCannotBePersistedToRoute',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { assign } from '@xstate/immer';
import { send } from 'xstate';
import { DepGraphStateNodeConfig } from './interfaces';
import { ProjectGraphStateNodeConfig } from './interfaces';

export const focusedStateConfig: DepGraphStateNodeConfig = {
export const focusedStateConfig: ProjectGraphStateNodeConfig = {
entry: [
assign((ctx, event) => {
if (event.type !== 'focusProject') return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { getGraphService } from './graph.service';
import { getGraphService } from '../../machines/graph.service';

export const graphActor = (callback, receive) => {
const graphService = getGraphService();

receive((e) => {
const { selectedProjectNames, perfReport } = graphService.handleEvent(e);
const { selectedProjectNames, perfReport } =
graphService.handleProjectEvent(e);
callback({
type: 'setSelectedProjectsFromGraph',
selectedProjectNames,
Expand Down
113 changes: 113 additions & 0 deletions graph/client/src/app/feature-projects/machines/interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { GraphPerfReport } from '../../interfaces';
// nx-ignore-next-line
import {
ProjectGraphDependency,
ProjectGraphProjectNode,
} from 'nx/src/config/project-graph';
import { ActionObject, ActorRef, State, StateNodeConfig } from 'xstate';
import { GraphRenderEvents, RouteEvents } from '../../machines/interfaces';

// The hierarchical schema for the states
export interface ProjectGraphSchema {
states: {
idle: {};
unselected: {};
focused: {};
textFiltered: {};
customSelected: {};
tracing: {};
};
}

export type TracingAlgorithmType = 'shortest' | 'all';

// The events that the machine handles
export type ProjectGraphMachineEvents =
| {
type: 'setSelectedProjectsFromGraph';
selectedProjectNames: string[];
perfReport: GraphPerfReport;
}
| { type: 'selectProject'; projectName: string }
| { type: 'deselectProject'; projectName: string }
| { type: 'selectProjects'; projectNames: string[] }
| { type: 'deselectProjects'; projectNames: string[] }
| { type: 'selectAll' }
| { type: 'deselectAll' }
| { type: 'selectAffected' }
| { type: 'setGroupByFolder'; groupByFolder: boolean }
| { type: 'setTracingStart'; projectName: string }
| { type: 'setTracingEnd'; projectName: string }
| { type: 'clearTraceStart' }
| { type: 'clearTraceEnd' }
| { type: 'setTracingAlgorithm'; algorithm: TracingAlgorithmType }
| { type: 'setCollapseEdges'; collapseEdges: boolean }
| { type: 'setIncludeProjectsByPath'; includeProjectsByPath: boolean }
| { type: 'incrementSearchDepth' }
| { type: 'decrementSearchDepth' }
| { type: 'setSearchDepthEnabled'; searchDepthEnabled: boolean }
| { type: 'setSearchDepth'; searchDepth: number }
| { type: 'focusProject'; projectName: string }
| { type: 'unfocusProject' }
| { type: 'filterByText'; search: string }
| { type: 'clearTextFilter' }
| {
type: 'notifyProjectGraphSetProjects';
projects: ProjectGraphProjectNode[];
dependencies: Record<string, ProjectGraphDependency[]>;
affectedProjects: string[];
workspaceLayout: {
libsDir: string;
appsDir: string;
};
}
| {
type: 'updateGraph';
projects: ProjectGraphProjectNode[];
dependencies: Record<string, ProjectGraphDependency[]>;
};

// The context (extended state) of the machine
export interface ProjectGraphContext {
projects: ProjectGraphProjectNode[];
dependencies: Record<string, ProjectGraphDependency[]>;
affectedProjects: string[];
selectedProjects: string[];
focusedProject: string | null;
textFilter: string;
includePath: boolean;
searchDepth: number;
searchDepthEnabled: boolean;
groupByFolder: boolean;
collapseEdges: boolean;
workspaceLayout: {
libsDir: string;
appsDir: string;
};
graphActor: ActorRef<GraphRenderEvents>;
routeSetterActor: ActorRef<RouteEvents>;
routeListenerActor: ActorRef<ProjectGraphMachineEvents>;
lastPerfReport: GraphPerfReport;
tracing: {
start: string;
end: string;
algorithm: TracingAlgorithmType;
};
}

export type ProjectGraphStateNodeConfig = StateNodeConfig<
ProjectGraphContext,
{},
ProjectGraphMachineEvents,
ActionObject<ProjectGraphContext, ProjectGraphMachineEvents>
>;

export type ProjectGraphState = State<
ProjectGraphContext,
ProjectGraphMachineEvents,
any,
{
value: any;
context: ProjectGraphContext;
}
>;
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { assign } from '@xstate/immer';
import { createMachine, Machine, send, spawn } from 'xstate';
import { createMachine, send, spawn } from 'xstate';
import { customSelectedStateConfig } from './custom-selected.state';
import { focusedStateConfig } from './focused.state';
import { graphActor } from './graph.actor';
import {
ProjectGraphContext,
ProjectGraphSchema,
ProjectGraphEvents,
} from './interfaces';
import { createRouteMachine } from './route-setter.machine';
import { createRouteMachine } from '../../machines/route-setter.machine';
import { textFilteredStateConfig } from './text-filtered.state';
import { tracingStateConfig } from './tracing.state';
import { unselectedStateConfig } from './unselected.state';
import { ProjectGraphContext, ProjectGraphMachineEvents } from './interfaces';

export const initialContext: ProjectGraphContext = {
projects: [],
Expand Down Expand Up @@ -46,11 +42,11 @@ export const initialContext: ProjectGraphContext = {

export const projectGraphMachine = createMachine<
ProjectGraphContext,
ProjectGraphEvents
ProjectGraphMachineEvents
>(
{
predictableActionArguments: true,
id: 'DepGraph',
id: 'project-graph',
initial: 'idle',
context: initialContext,
states: {
Expand Down
59 changes: 59 additions & 0 deletions graph/client/src/app/feature-projects/machines/selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// nx-ignore-next-line
import type { ProjectGraphProjectNode } from '@nrwl/devkit';
import { ProjectGraphSelector } from '../hooks/use-project-graph-selector';
import { GraphPerfReport, WorkspaceLayout } from '../../interfaces';
import { TracingAlgorithmType } from './interfaces';

export const allProjectsSelector: ProjectGraphSelector<
ProjectGraphProjectNode[]
> = (state) => state.context.projects;

export const workspaceLayoutSelector: ProjectGraphSelector<WorkspaceLayout> = (
state
) => state.context.workspaceLayout;

export const selectedProjectNamesSelector: ProjectGraphSelector<string[]> = (
state
) => state.context.selectedProjects;

export const projectIsSelectedSelector: ProjectGraphSelector<boolean> = (
state
) => state.context.selectedProjects.length > 0;

export const lastPerfReportSelector: ProjectGraphSelector<GraphPerfReport> = (
state
) => state.context.lastPerfReport;

export const focusedProjectNameSelector: ProjectGraphSelector<string> = (
state
) => state.context.focusedProject;

export const searchDepthSelector: ProjectGraphSelector<{
searchDepth: number;
searchDepthEnabled: boolean;
}> = (state) => ({
searchDepth: state.context.searchDepth,
searchDepthEnabled: state.context.searchDepthEnabled,
});

export const includePathSelector: ProjectGraphSelector<boolean> = (state) =>
state.context.includePath;

export const groupByFolderSelector: ProjectGraphSelector<boolean> = (state) =>
state.context.groupByFolder;

export const collapseEdgesSelector: ProjectGraphSelector<boolean> = (state) =>
state.context.collapseEdges;

export const textFilterSelector: ProjectGraphSelector<string> = (state) =>
state.context.textFilter;

export const hasAffectedProjectsSelector: ProjectGraphSelector<boolean> = (
state
) => state.context.affectedProjects.length > 0;

export const getTracingInfo: ProjectGraphSelector<{
start: string;
end: string;
algorithm: TracingAlgorithmType;
}> = (state) => state.context.tracing;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { assign } from '@xstate/immer';
import { send } from 'xstate';
import { DepGraphStateNodeConfig } from './interfaces';
import { ProjectGraphStateNodeConfig } from './interfaces';

export const textFilteredStateConfig: DepGraphStateNodeConfig = {
export const textFilteredStateConfig: ProjectGraphStateNodeConfig = {
entry: [
assign((ctx, event) => {
if (event.type !== 'filterByText') return;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { assign } from '@xstate/immer';
import { DepGraphStateNodeConfig } from './interfaces';
import { ProjectGraphStateNodeConfig } from './interfaces';

export const tracingStateConfig: DepGraphStateNodeConfig = {
export const tracingStateConfig: ProjectGraphStateNodeConfig = {
entry: [
assign((ctx, event) => {
if (event.type === 'setTracingStart') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { assign } from '@xstate/immer';
import { send, spawn } from 'xstate';
import { DepGraphStateNodeConfig } from './interfaces';
import { routeListener } from './route-listener.actor';
import { routeListener } from '../../machines/route-listener.actor';
import { ProjectGraphStateNodeConfig } from './interfaces';

export const unselectedStateConfig: DepGraphStateNodeConfig = {
export const unselectedStateConfig: ProjectGraphStateNodeConfig = {
entry: [
'notifyGraphHideAllProjects',
assign((ctx, event) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import {
CollapseEdgesPanel,
CollapseEdgesPanelProps,
} from './collapse-edges-panel';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { CollapseEdgesPanel } from './collapse-edges-panel';

export default {
component: CollapseEdgesPanel,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import {
FocusedProjectPanel,
FocusedProjectPanelProps,
} from './focused-project-panel';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { FocusedProjectPanel } from './focused-project-panel';

export default {
component: FocusedProjectPanel,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import {
DisplayOptionsPanelProps,
GroupByFolderPanel,
} from './group-by-folder-panel';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { GroupByFolderPanel } from './group-by-folder-panel';

export default {
component: GroupByFolderPanel,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import RankDirPanel from './rankdir-panel';

export default {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Menu } from '@headlessui/react';
import {
ArrowsUpDownIcon,
ArrowsRightLeftIcon,
ArrowsUpDownIcon,
} from '@heroicons/react/24/outline';
import { useEffect, useState } from 'react';
import {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { SearchDepth, SearchDepthProps } from './search-depth';
import { ComponentMeta, ComponentStory } from '@storybook/react';
import { SearchDepth } from './search-depth';

export default {
component: SearchDepth,
Expand Down
Loading

1 comment on commit c18ec6c

@vercel
Copy link

@vercel vercel bot commented on c18ec6c Nov 11, 2022

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-dev-git-master-nrwl.vercel.app
nx.dev
nx-five.vercel.app

Please sign in to comment.