Skip to content

Commit

Permalink
feat(graph): add button to toggle graph rankDir under feature flag (#…
Browse files Browse the repository at this point in the history
…12646)

Co-authored-by: Philip Fulcher <philip@nrwl.io>
  • Loading branch information
dustyhorizon and philipjfulcher committed Nov 1, 2022
1 parent 1c0c00e commit 5577bfb
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 8 deletions.
40 changes: 40 additions & 0 deletions graph/client-e2e/src/integration/app.spec.ts
Expand Up @@ -393,3 +393,43 @@ describe('theme preferences', () => {
});
});
});

describe('graph layout direction preferences', () => {
let rankDir: string;
before(() => {
cy.visit('/');
rankDir = 'TB';
});

it('should initialize localstorage with default graph layout direction', () => {
expect(localStorage.getItem('nx-dep-graph-rankdir')).eq(rankDir);
});

describe('left-to-right graph layout direction is set as preferred', () => {
before(() => {
cy.get('[data-cy="lr-rankdir-button"]').click();
});

it('should set left-to-right graph layout direction', () => {
cy.log('Localstorage is: ', localStorage.getItem('nx-dep-graph-rankdir'));
expect(localStorage.getItem('nx-dep-graph-rankdir')).eq('LR');
cy.get('[data-cy="tb-rankdir-button"]').should(
(elem) => expect(elem).to.exist
);
});
});

describe('top-to-bottom graph layout direction is set as preferred', () => {
before(() => {
cy.get('[data-cy="tb-rankdir-button"]').click();
});

it('should set top-to-bottom graph layout direction', () => {
cy.log('Localstorage is: ', localStorage.getItem('nx-dep-graph-rankdir'));
expect(localStorage.getItem('nx-dep-graph-rankdir')).eq('TB');
cy.get('[data-cy="lr-rankdir-button"]').should(
(elem) => expect(elem).to.exist
);
});
});
});
2 changes: 2 additions & 0 deletions graph/client/src/app/app.tsx
@@ -1,8 +1,10 @@
import { Shell } from './shell';
import { GlobalStateProvider } from './state.provider';
import { themeInit } from './theme-resolver';
import { rankDirInit } from './rankdir-resolver';

themeInit();
rankDirInit();

export function App() {
return (
Expand Down
32 changes: 25 additions & 7 deletions graph/client/src/app/machines/graph.ts
Expand Up @@ -8,6 +8,7 @@ import cy from 'cytoscape';
import cytoscapeDagre from 'cytoscape-dagre';
import popper from 'cytoscape-popper';
import { edgeStyles, nodeStyles } from '../styles-graph';
import { selectValueByRankDirStatic } from '../rankdir-resolver';
import { selectValueByThemeStatic } from '../theme-resolver';
import { GraphTooltipService } from '../tooltip-service';
import {
Expand All @@ -19,6 +20,15 @@ import {
import { GraphPerfReport, GraphRenderEvents } from './interfaces';
import { getEnvironmentConfig } from '../hooks/use-environment-config';

const cytoscapeDagreConfig = {
name: 'dagre',
nodeDimensionsIncludeLabels: true,
rankSep: 75,
rankDir: 'TB',
edgeSep: 50,
ranker: 'network-simplex',
} as CytoscapeDagreConfig;

export class GraphService {
private traversalGraph: cy.Core;
private renderGraph: cy.Core;
Expand Down Expand Up @@ -130,13 +140,9 @@ export class GraphService {

elements
.layout({
name: 'dagre',
nodeDimensionsIncludeLabels: true,
rankSep: 75,
rankDir: 'TB',
edgeSep: 50,
ranker: 'network-simplex',
} as CytoscapeDagreConfig)
...cytoscapeDagreConfig,
...{ rankDir: selectValueByRankDirStatic('TB', 'LR') },
})
.run();

if (this.collapseEdges) {
Expand Down Expand Up @@ -677,4 +683,16 @@ export class GraphService {
this.renderGraph.mount(container);
}
}

setRankDir(rankDir: 'TB' | 'LR') {
if (this.renderGraph) {
const elements = this.renderGraph.elements();
elements
.layout({
...cytoscapeDagreConfig,
...{ rankDir: rankDir },
} as CytoscapeDagreConfig)
.run();
}
}
}
33 changes: 33 additions & 0 deletions graph/client/src/app/rankdir-resolver.tsx
@@ -0,0 +1,33 @@
import { getGraphService } from './machines/graph.service';

export const localStorageRankDirKey = 'nx-dep-graph-rankdir';
export type RankDir = 'TB' | 'LR';
export let currentRankDir: RankDir;

export function rankDirInit() {
const rankDir =
(localStorage.getItem(localStorageRankDirKey) as RankDir) ?? 'TB';
rankDirResolver(rankDir);
}

export function rankDirResolver(rankDir: RankDir) {
currentRankDir = rankDir;
localStorage.setItem(localStorageRankDirKey, rankDir);
getGraphService().setRankDir(currentRankDir);
}

export function selectValueByRankDirDynamic<T>(
topBottomSetting: T,
leftRightSetting: T
): () => T {
return () => selectValueByRankDirStatic(topBottomSetting, leftRightSetting);
}

// The function exists because some places do not support selectDynamically
// It also prevents the dynamic change of rankDir for certain elements like tippy
export function selectValueByRankDirStatic<T>(
topBottomSetting: T,
leftRightSetting: T
): T {
return currentRankDir === 'TB' ? topBottomSetting : leftRightSetting;
}
12 changes: 12 additions & 0 deletions graph/client/src/app/sidebar/rankdir-panel.stories.tsx
@@ -0,0 +1,12 @@
import { ComponentStory, ComponentMeta } from '@storybook/react';
import RankDirPanel from './rankdir-panel';

export default {
component: RankDirPanel,
title: 'Project Graph/RankDirPanel',
} as ComponentMeta<typeof RankDirPanel>;

const Template: ComponentStory<typeof RankDirPanel> = () => <RankDirPanel />;

export const Primary = Template.bind({});
Primary.args = {};
50 changes: 50 additions & 0 deletions graph/client/src/app/sidebar/rankdir-panel.tsx
@@ -0,0 +1,50 @@
import { Menu } from '@headlessui/react';
import {
ArrowsUpDownIcon,
ArrowsRightLeftIcon,
} from '@heroicons/react/24/outline';
import { useEffect, useState } from 'react';
import {
localStorageRankDirKey,
RankDir,
rankDirResolver,
} from '../rankdir-resolver';

export default function RankdirPanel(): JSX.Element {
const [rankDir, setRankDir] = useState(
(localStorage.getItem(localStorageRankDirKey) as RankDir) || 'TB'
);

useEffect(() => {
rankDirResolver(rankDir);
}, [rankDir]);

return (
<div className="relative inline-block text-left">
<button
className="inline-flex w-full justify-center rounded-md p-2 text-sm font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 dark:text-sky-500"
data-cy="rankdir-change-button"
>
<span className="sr-only">Graph layout direction switcher</span>
{rankDir === 'TB' && (
<button
title="Set graph direction to left-to-right"
data-cy="lr-rankdir-button"
onClick={() => setRankDir('LR')}
>
<ArrowsUpDownIcon className="h-4 w-4" aria-hidden="true" />
</button>
)}
{rankDir === 'LR' && (
<button
title="Set graph direction to top-to-bottom"
data-cy="tb-rankdir-button"
onClick={() => setRankDir('TB')}
>
<ArrowsRightLeftIcon className="h-4 w-4" aria-hidden="true" />
</button>
)}
</button>
</div>
);
}
8 changes: 7 additions & 1 deletion graph/client/src/app/sidebar/sidebar.tsx
Expand Up @@ -20,6 +20,7 @@ import ProjectList from './project-list';
import SearchDepth from './search-depth';
import ShowHideProjects from './show-hide-projects';
import TextFilterPanel from './text-filter-panel';
import RankDirPanel from './rankdir-panel';
import ThemePanel from './theme-panel';
import TracingPanel from './tracing-panel';
import { TracingAlgorithmType } from '../machines/interfaces';
Expand Down Expand Up @@ -133,7 +134,12 @@ export function Sidebar(): JSX.Element {
<path d="M11.987 14.138l-3.132 4.923-5.193-8.427-.012 8.822H0V4.544h3.691l5.247 8.833.005-3.998 3.044 4.759zm.601-5.761c.024-.048 0-3.784.008-3.833h-3.65c.002.059-.005 3.776-.003 3.833h3.645zm5.634 4.134a2.061 2.061 0 0 0-1.969 1.336 1.963 1.963 0 0 1 2.343-.739c.396.161.917.422 1.33.283a2.1 2.1 0 0 0-1.704-.88zm3.39 1.061c-.375-.13-.8-.277-1.109-.681-.06-.08-.116-.17-.176-.265a2.143 2.143 0 0 0-.533-.642c-.294-.216-.68-.322-1.18-.322a2.482 2.482 0 0 0-2.294 1.536 2.325 2.325 0 0 1 4.002.388.75.75 0 0 0 .836.334c.493-.105.46.36 1.203.518v-.133c-.003-.446-.246-.55-.75-.733zm2.024 1.266a.723.723 0 0 0 .347-.638c-.01-2.957-2.41-5.487-5.37-5.487a5.364 5.364 0 0 0-4.487 2.418c-.01-.026-1.522-2.39-1.538-2.418H8.943l3.463 5.423-3.379 5.32h3.54l1.54-2.366 1.568 2.366h3.541l-3.21-5.052a.7.7 0 0 1-.084-.32 2.69 2.69 0 0 1 2.69-2.691h.001c1.488 0 1.736.89 2.057 1.308.634.826 1.9.464 1.9 1.541a.707.707 0 0 0 1.066.596zm.35.133c-.173.372-.56.338-.755.639-.176.271.114.412.114.412s.337.156.538-.311c.104-.231.14-.488.103-.74z" />
</svg>

<ThemePanel />
<div className="align-right">
<ExperimentalFeature>
<RankDirPanel />
</ExperimentalFeature>
<ThemePanel />
</div>
</div>
</div>

Expand Down

1 comment on commit 5577bfb

@vercel
Copy link

@vercel vercel bot commented on 5577bfb Nov 1, 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-five.vercel.app
nx-dev-nrwl.vercel.app
nx.dev
nx-dev-git-master-nrwl.vercel.app

Please sign in to comment.