Navigation Menu

Skip to content

Commit

Permalink
feat(dep-graph): add experimental support for finding path between pr…
Browse files Browse the repository at this point in the history
…ojects (#9643)

* feat(dep-graph): add experimental support for tracing paths between projects

* feat(graph): add algorithm for finding all paths between projects

* cleanup(dep-graph): clean-up edge tooltip

* cleanup(dep-graph): fix watch mode dev environment
  • Loading branch information
philipjfulcher committed Apr 2, 2022
1 parent 05a9544 commit dbe942c
Show file tree
Hide file tree
Showing 25 changed files with 17,931 additions and 401 deletions.
24 changes: 12 additions & 12 deletions dep-graph/client-e2e/src/integration/app.spec.ts
Expand Up @@ -55,20 +55,20 @@ describe('dep-graph-client', () => {

it('should filter projects', () => {
getTextFilterInput().type('nx-dev');
getCheckedProjectItems().should('have.length', 9);
getCheckedProjectItems().should('have.length', 15);
});

it('should clear selection on reset', () => {
getTextFilterInput().type('nx-dev');
getCheckedProjectItems().should('have.length', 9);
getCheckedProjectItems().should('have.length', 15);
getTextFilterReset().click();
getCheckedProjectItems().should('have.length', 0);
});
});

describe('selecting a different project', () => {
it('should change the available projects', () => {
getProjectItems().should('have.length', 53);
getProjectItems().should('have.length', 62);
cy.get('[data-cy=project-select]').select('Ocean', { force: true });
getProjectItems().should('have.length', 124);
});
Expand All @@ -77,14 +77,14 @@ describe('dep-graph-client', () => {
describe('select all button', () => {
it('should check all project items', () => {
getSelectAllButton().scrollIntoView().click({ force: true });
getCheckedProjectItems().should('have.length', 53);
getCheckedProjectItems().should('have.length', 62);
});
});

describe('deselect all button', () => {
it('should uncheck all project items', () => {
getDeselectAllButton().click();
getUncheckedProjectItems().should('have.length', 53);
getUncheckedProjectItems().should('have.length', 62);
getSelectProjectsMessage().should('be.visible');
});
});
Expand Down Expand Up @@ -147,7 +147,7 @@ describe('dep-graph-client', () => {
cy.contains('nx-dev').scrollIntoView().should('be.visible');
cy.get('[data-project="nx-dev"]').prev('button').click({ force: true });

getCheckedProjectItems().should('have.length', 10);
getCheckedProjectItems().should('have.length', 15);
});
});

Expand All @@ -156,22 +156,22 @@ describe('dep-graph-client', () => {
cy.get('[data-project="nx-dev"]').prev('button').click({ force: true });
getUnfocusProjectButton().click();

getUncheckedProjectItems().should('have.length', 53);
getUncheckedProjectItems().should('have.length', 62);
});
});

describe('text filtering', () => {
it('should filter projects by text when pressing enter', () => {
getTextFilterInput().type('nx-dev{enter}');

getCheckedProjectItems().should('have.length', 9);
getCheckedProjectItems().should('have.length', 15);
});

it('should include projects in path when option is checked', () => {
getTextFilterInput().type('nx-dev');
getIncludeProjectsInPathButton().click();

getCheckedProjectItems().should('have.length', 17);
getCheckedProjectItems().should('have.length', 24);
});
});

Expand Down Expand Up @@ -229,7 +229,7 @@ describe('loading dep-graph client with url params', () => {
// wait for first graph to finish loading
cy.wait('@getGraph');

getCheckedProjectItems().should('have.length', 10);
getCheckedProjectItems().should('have.length', 15);
});

it('should focus projects with search depth', () => {
Expand All @@ -240,7 +240,7 @@ describe('loading dep-graph client with url params', () => {
// wait for first graph to finish loading
cy.wait('@getGraph');

getCheckedProjectItems().should('have.length', 8);
getCheckedProjectItems().should('have.length', 11);
getSearchDepthCheckbox().should('exist');
});

Expand All @@ -263,7 +263,7 @@ describe('loading dep-graph client with url params', () => {
// wait for first graph to finish loading
cy.wait('@getGraph');

getCheckedProjectItems().should('have.length', 53);
getCheckedProjectItems().should('have.length', 62);
});
});

Expand Down
39 changes: 39 additions & 0 deletions dep-graph/client/src/app/edge-tooltip.tsx
@@ -0,0 +1,39 @@
export interface EdgeNodeTooltipProps {
type: 'static' | 'dynamic' | 'implicit';
source: string;
target: string;
fileDependencies: Array<{ fileName: string }>;
}
function EdgeNodeTooltip({
type,
source,
target,
fileDependencies,
}: EdgeNodeTooltipProps) {
return (
<div>
<h4 className={type !== 'implicit' ? 'mb-3' : ''}>
<span className="tag">{type ?? 'unknown'}</span>
{source} &rarr; {target}
</h4>
{type !== 'implicit' ? (
<div className="rounded-md border border-gray-200">
<div className="rounded-t-md bg-gray-50 px-4 py-2 text-xs font-medium uppercase text-gray-500">
<span>Files</span>
</div>
<ul className="max-h-[300px] divide-y divide-gray-200 overflow-auto">
{fileDependencies.map((fileDep) => (
<li className="dark:text-sidebar-text-dark whitespace-nowrap px-4 py-2 text-sm font-medium text-gray-900">
<span className="block truncate font-normal">
{fileDep.fileName}
</span>
</li>
))}
</ul>
</div>
) : null}
</div>
);
}

export default EdgeNodeTooltip;
18 changes: 18 additions & 0 deletions dep-graph/client/src/app/icons/flag.tsx
@@ -0,0 +1,18 @@
function Flag(props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<path
fillRule="evenodd"
d="M3 6a3 3 0 013-3h10a1 1 0 01.8 1.6L14.25 8l2.55 3.4A1 1 0 0116 13H6a1 1 0 00-1 1v3a1 1 0 11-2 0V6z"
clipRule="evenodd"
/>
</svg>
);
}

export default Flag;
14 changes: 14 additions & 0 deletions dep-graph/client/src/app/icons/map-marker.tsx
@@ -0,0 +1,14 @@
function MapMarker(props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
{...props}
>
<path d="M10 6a2 2 0 110-4 2 2 0 010 4zM10 12a2 2 0 110-4 2 2 0 010 4zM10 18a2 2 0 110-4 2 2 0 010 4z" />
</svg>
);
}

export default MapMarker;
20 changes: 20 additions & 0 deletions dep-graph/client/src/app/icons/x-circle-outline.tsx
@@ -0,0 +1,20 @@
function XCircleOutline(props) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
{...props}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="2"
d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
);
}

export default XCircleOutline;
37 changes: 37 additions & 0 deletions dep-graph/client/src/app/machines/dep-graph.machine.ts
Expand Up @@ -10,6 +10,7 @@ import {
} from './interfaces';
import { createRouteMachine } from './route-setter.machine';
import { textFilteredStateConfig } from './text-filtered.state';
import { tracingStateConfig } from './tracing.state';
import { unselectedStateConfig } from './unselected.state';

export const initialContext: DepGraphContext = {
Expand All @@ -36,6 +37,10 @@ export const initialContext: DepGraphContext = {
numNodes: 0,
renderTime: 0,
},
tracing: {
start: null,
end: null,
},
};

export const depGraphMachine = Machine<
Expand All @@ -53,6 +58,7 @@ export const depGraphMachine = Machine<
customSelected: customSelectedStateConfig,
focused: focusedStateConfig,
textFiltered: textFilteredStateConfig,
tracing: tracingStateConfig,
},
on: {
initGraph: {
Expand Down Expand Up @@ -114,6 +120,12 @@ export const depGraphMachine = Machine<
focusProject: {
target: 'focused',
},
setTracingStart: {
target: 'tracing',
},
setTracingEnd: {
target: 'tracing',
},
setCollapseEdges: {
actions: [
'setCollapseEdges',
Expand Down Expand Up @@ -262,6 +274,19 @@ export const depGraphMachine = Machine<
ctx.affectedProjects = event.affectedProjects;
}
}),
notifyGraphTracing: send(
(ctx, event) => {
return {
type: 'notifyGraphTracing',
start: ctx.tracing.start,
end: ctx.tracing.end,
};
},
{
to: (context) => context.graphActor,
}
),

notifyGraphShowProject: send(
(context, event) => {
if (event.type !== 'selectProject') return;
Expand Down Expand Up @@ -354,6 +379,18 @@ export const depGraphMachine = Machine<
to: (ctx) => ctx.routeSetterActor,
}
),
notifyRouteTracing: send(
(ctx) => {
return {
type: 'notifyRouteTracing',
start: ctx.tracing.start,
end: ctx.tracing.end,
};
},
{
to: (ctx) => ctx.routeSetterActor,
}
),
notifyRouteSearchDepth: send(
(ctx, event) => ({
type: 'notifyRouteSearchDepth',
Expand Down

0 comments on commit dbe942c

Please sign in to comment.