feat(dep-graph): launch path tracing (#9919)
This commit is contained in:
parent
5f12ce0f12
commit
3dc818f631
@ -1,6 +1,7 @@
|
||||
import {
|
||||
getCheckedProjectItems,
|
||||
getDeselectAllButton,
|
||||
getFocusButtonForProject,
|
||||
getGroupByFolderCheckbox,
|
||||
getImageDownloadButton,
|
||||
getIncludeProjectsInPathButton,
|
||||
@ -146,7 +147,7 @@ describe('dep-graph-client', () => {
|
||||
describe('focusing projects in sidebar', () => {
|
||||
it('should select appropriate projects', () => {
|
||||
cy.contains('nx-dev').scrollIntoView().should('be.visible');
|
||||
cy.get('[data-project="nx-dev"]').prev('button').click({ force: true });
|
||||
getFocusButtonForProject('nx-dev').click({ force: true });
|
||||
|
||||
getCheckedProjectItems().should('have.length', 11);
|
||||
});
|
||||
@ -154,7 +155,7 @@ describe('dep-graph-client', () => {
|
||||
|
||||
describe('unfocus button', () => {
|
||||
it('should uncheck all project items', () => {
|
||||
cy.get('[data-project="nx-dev"]').prev('button').click({ force: true });
|
||||
getFocusButtonForProject('nx-dev').click({ force: true });
|
||||
getUnfocusProjectButton().click();
|
||||
|
||||
getUncheckedProjectItems().should('have.length', 62);
|
||||
@ -182,12 +183,12 @@ describe('dep-graph-client', () => {
|
||||
});
|
||||
|
||||
it('should be shown when a project is selected', () => {
|
||||
cy.get('[data-project="nx-dev"]').prev('button').click({ force: true });
|
||||
cy.get('[data-project="nx-dev"]').click({ force: true });
|
||||
getImageDownloadButton().should('not.have.class', 'opacity-0');
|
||||
});
|
||||
|
||||
it('should be hidden when no more projects are selected', () => {
|
||||
cy.get('[data-project="nx-dev"]').prev('button').click({ force: true });
|
||||
cy.get('[data-project="nx-dev"]').click({ force: true });
|
||||
getDeselectAllButton().click();
|
||||
getImageDownloadButton().should('have.class', 'opacity-0');
|
||||
});
|
||||
@ -196,7 +197,7 @@ describe('dep-graph-client', () => {
|
||||
describe('setting url params', () => {
|
||||
it('should set focused project', () => {
|
||||
cy.contains('nx-dev').scrollIntoView().should('be.visible');
|
||||
cy.get('[data-project="nx-dev"]').prev('button').click({ force: true });
|
||||
getFocusButtonForProject('nx-dev').click({ force: true });
|
||||
|
||||
cy.url().should('contain', 'focus=nx-dev');
|
||||
});
|
||||
|
||||
@ -29,3 +29,6 @@ export const getIncludeProjectsInPathButton = () =>
|
||||
|
||||
export const getImageDownloadButton = () =>
|
||||
cy.get('[data-cy=downloadImageButton]');
|
||||
|
||||
export const getFocusButtonForProject = (projectName: string) =>
|
||||
cy.get(`[data-cy="focus-button-${projectName}"]`);
|
||||
|
||||
@ -23,8 +23,8 @@ describe('dep-graph-client in watch mode', () => {
|
||||
// TODO: This test is getting flaky but was fixed by increasing the tick time between checks
|
||||
// Figure out a better way to test this
|
||||
it('should retain selected projects as new libs are created', () => {
|
||||
cy.contains('existing-app-1').siblings('button').click();
|
||||
cy.contains('existing-lib-1').siblings('button').click();
|
||||
cy.get('[data-project="existing-app-1"]').click();
|
||||
cy.get('[data-project="existing-lib-1"]').click();
|
||||
|
||||
cy.tick(6000);
|
||||
|
||||
|
||||
@ -40,6 +40,7 @@ export const initialContext: DepGraphContext = {
|
||||
tracing: {
|
||||
start: null,
|
||||
end: null,
|
||||
algorithm: 'shortest',
|
||||
},
|
||||
};
|
||||
|
||||
@ -211,6 +212,15 @@ export const depGraphMachine = Machine<
|
||||
setSearchDepth: {
|
||||
actions: ['setSearchDepth', 'notifyRouteSearchDepth'],
|
||||
},
|
||||
setTracingAlgorithm: {
|
||||
actions: [
|
||||
assign((ctx, event) => {
|
||||
ctx.tracing.algorithm = event.algorithm;
|
||||
}),
|
||||
'notifyRouteTracing',
|
||||
'notifyGraphTracing',
|
||||
],
|
||||
},
|
||||
filterByText: {
|
||||
target: 'textFiltered',
|
||||
},
|
||||
@ -280,6 +290,7 @@ export const depGraphMachine = Machine<
|
||||
type: 'notifyGraphTracing',
|
||||
start: ctx.tracing.start,
|
||||
end: ctx.tracing.end,
|
||||
algorithm: ctx.tracing.algorithm,
|
||||
};
|
||||
},
|
||||
{
|
||||
@ -385,6 +396,7 @@ export const depGraphMachine = Machine<
|
||||
type: 'notifyRouteTracing',
|
||||
start: ctx.tracing.start,
|
||||
end: ctx.tracing.end,
|
||||
algorithm: ctx.tracing.algorithm,
|
||||
};
|
||||
},
|
||||
{
|
||||
|
||||
@ -110,8 +110,11 @@ export class GraphService {
|
||||
|
||||
case 'notifyGraphTracing':
|
||||
if (event.start && event.end) {
|
||||
this.traceProjects(event.start, event.end);
|
||||
// this.traceAllProjects(event.start, event.end);
|
||||
if (event.algorithm === 'shortest') {
|
||||
this.traceProjects(event.start, event.end);
|
||||
} else {
|
||||
this.traceAllProjects(event.start, event.end);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -390,13 +393,6 @@ export class GraphService {
|
||||
if (iterations >= 1000) {
|
||||
console.log('failsafe triggered!');
|
||||
}
|
||||
paths.forEach((currentPath) => {
|
||||
console.log(
|
||||
currentPath
|
||||
.map((path) => path.map((element) => element.id()))
|
||||
.join(' => ')
|
||||
);
|
||||
});
|
||||
|
||||
let finalCollection = this.traversalGraph.collection();
|
||||
|
||||
@ -413,11 +409,10 @@ export class GraphService {
|
||||
}
|
||||
});
|
||||
|
||||
console.log(finalCollection.length);
|
||||
|
||||
finalCollection.union(finalCollection.ancestors());
|
||||
console.log(finalCollection.map((element) => element.id()));
|
||||
this.transferToRenderGraph(finalCollection);
|
||||
this.transferToRenderGraph(
|
||||
finalCollection.union(finalCollection.ancestors())
|
||||
);
|
||||
}
|
||||
|
||||
private transferToRenderGraph(elements: cy.Collection) {
|
||||
|
||||
@ -22,6 +22,8 @@ export interface GraphPerfReport {
|
||||
numNodes: number;
|
||||
numEdges: number;
|
||||
}
|
||||
|
||||
export type TracingAlgorithmType = 'shortest' | 'all';
|
||||
// The events that the machine handles
|
||||
|
||||
export type DepGraphUIEvents =
|
||||
@ -40,6 +42,7 @@ export type DepGraphUIEvents =
|
||||
| { type: 'setTracingEnd'; projectName: string }
|
||||
| { type: 'clearTraceStart' }
|
||||
| { type: 'clearTraceEnd' }
|
||||
| { type: 'setTracingAlgorithm'; algorithm: TracingAlgorithmType }
|
||||
| { type: 'setCollapseEdges'; collapseEdges: boolean }
|
||||
| { type: 'setIncludeProjectsByPath'; includeProjectsByPath: boolean }
|
||||
| { type: 'incrementSearchDepth' }
|
||||
@ -126,6 +129,7 @@ export type GraphRenderEvents =
|
||||
type: 'notifyGraphTracing';
|
||||
start: string;
|
||||
end: string;
|
||||
algorithm: TracingAlgorithmType;
|
||||
};
|
||||
|
||||
export type RouteEvents =
|
||||
@ -156,7 +160,12 @@ export type RouteEvents =
|
||||
type: 'notifyRouteSelectAffected';
|
||||
}
|
||||
| { type: 'notifyRouteClearSelect' }
|
||||
| { type: 'notifyRouteTracing'; start: string; end: string };
|
||||
| {
|
||||
type: 'notifyRouteTracing';
|
||||
start: string;
|
||||
end: string;
|
||||
algorithm: TracingAlgorithmType;
|
||||
};
|
||||
|
||||
export type AllEvents = DepGraphUIEvents | GraphRenderEvents | RouteEvents;
|
||||
|
||||
@ -184,6 +193,7 @@ export interface DepGraphContext {
|
||||
tracing: {
|
||||
start: string;
|
||||
end: string;
|
||||
algorithm: TracingAlgorithmType;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -39,6 +39,12 @@ function parseSearchParamsToEvents(searchParams: string): DepGraphUIEvents[] {
|
||||
});
|
||||
}
|
||||
break;
|
||||
case 'traceAlgorithm':
|
||||
if (value === 'shortest' || value === 'all') {
|
||||
// this needs to go before other tracing options or else the default of 'shortest' gets used
|
||||
events.unshift({ type: 'setTracingAlgorithm', algorithm: value });
|
||||
}
|
||||
break;
|
||||
case 'traceStart':
|
||||
events.push({
|
||||
type: 'setTracingStart',
|
||||
|
||||
@ -10,7 +10,8 @@ type ParamKeys =
|
||||
| 'select'
|
||||
| 'collapseEdges'
|
||||
| 'traceStart'
|
||||
| 'traceEnd';
|
||||
| 'traceEnd'
|
||||
| 'traceAlgorithm';
|
||||
type ParamRecord = Record<ParamKeys, string | null>;
|
||||
|
||||
function reduceParamRecordToQueryString(params: ParamRecord): string {
|
||||
@ -37,6 +38,7 @@ export const createRouteMachine = () => {
|
||||
select: params.get('select'),
|
||||
traceStart: params.get('traceStart'),
|
||||
traceEnd: params.get('traceEnd'),
|
||||
traceAlgorithm: params.get('traceAlgorithm'),
|
||||
};
|
||||
|
||||
const initialContext = {
|
||||
@ -61,6 +63,7 @@ export const createRouteMachine = () => {
|
||||
collapseEdges: null,
|
||||
traceStart: null,
|
||||
traceEnd: null,
|
||||
traceAlgorithm: null,
|
||||
},
|
||||
},
|
||||
always: {
|
||||
@ -129,15 +132,17 @@ export const createRouteMachine = () => {
|
||||
},
|
||||
notifyRouteTracing: {
|
||||
actions: assign((ctx, event) => {
|
||||
if (event.start !== null && event.end !== null) {
|
||||
if (event.start !== null && event.end !== null && event.algorithm) {
|
||||
ctx.params.traceStart = event.start;
|
||||
ctx.params.traceEnd = event.end;
|
||||
ctx.params.traceAlgorithm = event.algorithm;
|
||||
|
||||
ctx.params.focus = null;
|
||||
ctx.params.select = null;
|
||||
} else {
|
||||
ctx.params.traceStart = null;
|
||||
ctx.params.traceEnd = null;
|
||||
ctx.params.traceAlgorithm = null;
|
||||
}
|
||||
}),
|
||||
},
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import type { ProjectGraphProjectNode } from '@nrwl/devkit';
|
||||
import { DepGraphSelector } from '../hooks/use-dep-graph-selector';
|
||||
import { WorkspaceLayout } from '../interfaces';
|
||||
import { GraphPerfReport } from './interfaces';
|
||||
import { GraphPerfReport, TracingAlgorithmType } from './interfaces';
|
||||
|
||||
export const allProjectsSelector: DepGraphSelector<
|
||||
ProjectGraphProjectNode[]
|
||||
@ -52,4 +52,5 @@ export const hasAffectedProjectsSelector: DepGraphSelector<boolean> = (state) =>
|
||||
export const getTracingInfo: DepGraphSelector<{
|
||||
start: string;
|
||||
end: string;
|
||||
algorithm: TracingAlgorithmType;
|
||||
}> = (state) => state.context.tracing;
|
||||
|
||||
@ -13,6 +13,15 @@ export const tracingStateConfig: DepGraphStateNodeConfig = {
|
||||
'notifyRouteTracing',
|
||||
'notifyGraphTracing',
|
||||
],
|
||||
exit: [
|
||||
assign((ctx, event) => {
|
||||
if (event.type !== 'setTracingStart' && event.type !== 'setTracingEnd') {
|
||||
ctx.tracing.start = null;
|
||||
ctx.tracing.end = null;
|
||||
}
|
||||
}),
|
||||
'notifyRouteTracing',
|
||||
],
|
||||
on: {
|
||||
clearTraceStart: {
|
||||
actions: [
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
import ExperimentalFeature from './experimental-feature';
|
||||
import { getDepGraphService } from './machines/dep-graph.service';
|
||||
|
||||
export interface ProjectNodeToolTipProps {
|
||||
@ -53,38 +52,36 @@ function ProjectNodeToolTip({ type, id, tags }: ProjectNodeToolTipProps) {
|
||||
<div className="flex">
|
||||
<button onClick={onFocus}>Focus</button>
|
||||
<button onClick={onExclude}>Exclude</button>
|
||||
<ExperimentalFeature>
|
||||
<button className="flex flex-row items-center" onClick={onStartTrace}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2 h-5 w-5 text-slate-500"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Start
|
||||
</button>
|
||||
<button className="flex flex-row items-center" onClick={onEndTrace}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2 h-5 w-5 text-slate-500"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<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>
|
||||
End
|
||||
</button>
|
||||
</ExperimentalFeature>
|
||||
<button className="flex flex-row items-center" onClick={onStartTrace}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2 h-5 w-5 text-slate-500"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<path
|
||||
fillRule="evenodd"
|
||||
d="M5.05 4.05a7 7 0 119.9 9.9L10 18.9l-4.95-4.95a7 7 0 010-9.9zM10 11a2 2 0 100-4 2 2 0 000 4z"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
Start
|
||||
</button>
|
||||
<button className="flex flex-row items-center" onClick={onEndTrace}>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
className="mr-2 h-5 w-5 text-slate-500"
|
||||
viewBox="0 0 20 20"
|
||||
fill="currentColor"
|
||||
>
|
||||
<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>
|
||||
End
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -1,14 +1,21 @@
|
||||
import { DocumentSearchIcon } from '@heroicons/react/solid';
|
||||
import {
|
||||
DocumentSearchIcon,
|
||||
FlagIcon,
|
||||
LocationMarkerIcon,
|
||||
} from '@heroicons/react/solid';
|
||||
// nx-ignore-next-line
|
||||
import type { ProjectGraphNode } from '@nrwl/devkit';
|
||||
import { useDepGraphService } from '../hooks/use-dep-graph';
|
||||
import { useDepGraphSelector } from '../hooks/use-dep-graph-selector';
|
||||
import {
|
||||
allProjectsSelector,
|
||||
getTracingInfo,
|
||||
selectedProjectNamesSelector,
|
||||
workspaceLayoutSelector,
|
||||
} from '../machines/selectors';
|
||||
import { parseParentDirectoriesFromFilePath } from '../util';
|
||||
import { TracingAlgorithmType } from '../machines/interfaces';
|
||||
import ExperimentalFeature from '../experimental-feature';
|
||||
|
||||
function getProjectsByType(type: string, projects: ProjectGraphNode[]) {
|
||||
return projects
|
||||
@ -23,6 +30,12 @@ interface SidebarProject {
|
||||
|
||||
type DirectoryProjectRecord = Record<string, SidebarProject[]>;
|
||||
|
||||
interface TracingInfo {
|
||||
start: string;
|
||||
end: string;
|
||||
algorithm: TracingAlgorithmType;
|
||||
}
|
||||
|
||||
function groupProjectsByDirectory(
|
||||
projects: ProjectGraphNode[],
|
||||
selectedProjects: string[],
|
||||
@ -58,17 +71,24 @@ function ProjectListItem({
|
||||
project,
|
||||
toggleProject,
|
||||
focusProject,
|
||||
startTrace,
|
||||
endTrace,
|
||||
tracingInfo,
|
||||
}: {
|
||||
project: SidebarProject;
|
||||
toggleProject: (projectId: string, currentlySelected: boolean) => void;
|
||||
focusProject: (projectId: string) => void;
|
||||
startTrace: (projectId: string) => void;
|
||||
endTrace: (projectId: string) => void;
|
||||
tracingInfo: TracingInfo;
|
||||
}) {
|
||||
return (
|
||||
<li className="relative block cursor-default select-none py-1 pl-3 pr-9 text-xs text-slate-600 dark:text-slate-400">
|
||||
<li className="relative block cursor-default select-none py-1 pl-2 pr-6 text-xs text-slate-600 dark:text-slate-400">
|
||||
<div className="flex items-center">
|
||||
<button
|
||||
data-cy={`focus-button-${project.projectGraphNode.name}`}
|
||||
type="button"
|
||||
className="flex rounded-md"
|
||||
className="mr-1 flex rounded-md"
|
||||
title="Focus on this library"
|
||||
onClick={() => focusProject(project.projectGraphNode.name)}
|
||||
>
|
||||
@ -76,9 +96,47 @@ function ProjectListItem({
|
||||
<DocumentSearchIcon className="h-5 w-5" />
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<ExperimentalFeature>
|
||||
<button
|
||||
type="button"
|
||||
className="mr-1 flex rounded-md"
|
||||
title="Start Trace"
|
||||
onClick={() => startTrace(project.projectGraphNode.name)}
|
||||
>
|
||||
<span
|
||||
className={`${
|
||||
tracingInfo.start === project.projectGraphNode.name
|
||||
? 'ring-blue-nx-base'
|
||||
: 'ring-slate-200 dark:ring-slate-600'
|
||||
} flex items-center rounded-md bg-white p-1 font-medium shadow-sm ring-1 transition hover:bg-slate-50 dark:bg-slate-800 dark:text-slate-400 dark:ring-slate-600 hover:dark:bg-slate-700`}
|
||||
>
|
||||
<LocationMarkerIcon className="h-5 w-5" />
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="flex rounded-md"
|
||||
title="End Trace"
|
||||
onClick={() => endTrace(project.projectGraphNode.name)}
|
||||
>
|
||||
<span
|
||||
className={`${
|
||||
tracingInfo.end === project.projectGraphNode.name
|
||||
? 'ring-blue-nx-base'
|
||||
: 'ring-slate-200 dark:ring-slate-600'
|
||||
} flex items-center rounded-md bg-white p-1 font-medium shadow-sm ring-1 transition hover:bg-slate-50 dark:bg-slate-800 dark:text-slate-400 dark:ring-slate-600 hover:dark:bg-slate-700`}
|
||||
>
|
||||
<FlagIcon className="h-5 w-5" />
|
||||
</span>
|
||||
</button>
|
||||
</ExperimentalFeature>
|
||||
|
||||
<label
|
||||
className="ml-3 block w-full cursor-pointer truncate rounded-md p-2 font-mono font-normal transition hover:bg-slate-50 hover:dark:bg-slate-700"
|
||||
className="ml-2 block w-full cursor-pointer truncate rounded-md p-2 font-mono font-normal transition hover:bg-slate-50 hover:dark:bg-slate-700"
|
||||
data-project={project.projectGraphNode.name}
|
||||
title={project.projectGraphNode.name}
|
||||
data-active={project.isSelected.toString()}
|
||||
onClick={() =>
|
||||
toggleProject(project.projectGraphNode.name, project.isSelected)
|
||||
@ -128,12 +186,18 @@ function SubProjectList({
|
||||
selectProject,
|
||||
deselectProject,
|
||||
focusProject,
|
||||
startTrace,
|
||||
endTrace,
|
||||
tracingInfo,
|
||||
}: {
|
||||
headerText: string;
|
||||
projects: SidebarProject[];
|
||||
selectProject: (projectName: string) => void;
|
||||
deselectProject: (projectName: string) => void;
|
||||
focusProject: (projectName: string) => void;
|
||||
startTrace: (projectId: string) => void;
|
||||
endTrace: (projectId: string) => void;
|
||||
tracingInfo: TracingInfo;
|
||||
}) {
|
||||
let sortedProjects = [...projects];
|
||||
sortedProjects.sort((a, b) => {
|
||||
@ -163,6 +227,9 @@ function SubProjectList({
|
||||
project={project}
|
||||
toggleProject={toggleProject}
|
||||
focusProject={focusProject}
|
||||
startTrace={startTrace}
|
||||
endTrace={endTrace}
|
||||
tracingInfo={tracingInfo}
|
||||
></ProjectListItem>
|
||||
);
|
||||
})}
|
||||
@ -173,6 +240,7 @@ function SubProjectList({
|
||||
|
||||
export function ProjectList() {
|
||||
const depGraphService = useDepGraphService();
|
||||
const tracingInfo = useDepGraphSelector(getTracingInfo);
|
||||
|
||||
function deselectProject(projectName: string) {
|
||||
depGraphService.send({ type: 'deselectProject', projectName });
|
||||
@ -186,6 +254,14 @@ export function ProjectList() {
|
||||
depGraphService.send({ type: 'focusProject', projectName });
|
||||
}
|
||||
|
||||
function startTrace(projectName: string) {
|
||||
depGraphService.send({ type: 'setTracingStart', projectName });
|
||||
}
|
||||
|
||||
function endTrace(projectName: string) {
|
||||
depGraphService.send({ type: 'setTracingEnd', projectName });
|
||||
}
|
||||
|
||||
const projects = useDepGraphSelector(allProjectsSelector);
|
||||
const workspaceLayout = useDepGraphSelector(workspaceLayoutSelector);
|
||||
const selectedProjects = useDepGraphSelector(selectedProjectNamesSelector);
|
||||
@ -229,6 +305,9 @@ export function ProjectList() {
|
||||
deselectProject={deselectProject}
|
||||
selectProject={selectProject}
|
||||
focusProject={focusProject}
|
||||
startTrace={startTrace}
|
||||
endTrace={endTrace}
|
||||
tracingInfo={tracingInfo}
|
||||
></SubProjectList>
|
||||
);
|
||||
})}
|
||||
@ -246,6 +325,9 @@ export function ProjectList() {
|
||||
deselectProject={deselectProject}
|
||||
selectProject={selectProject}
|
||||
focusProject={focusProject}
|
||||
startTrace={startTrace}
|
||||
endTrace={endTrace}
|
||||
tracingInfo={tracingInfo}
|
||||
></SubProjectList>
|
||||
);
|
||||
})}
|
||||
@ -263,6 +345,9 @@ export function ProjectList() {
|
||||
deselectProject={deselectProject}
|
||||
selectProject={selectProject}
|
||||
focusProject={focusProject}
|
||||
startTrace={startTrace}
|
||||
endTrace={endTrace}
|
||||
tracingInfo={tracingInfo}
|
||||
></SubProjectList>
|
||||
);
|
||||
})}
|
||||
|
||||
@ -23,6 +23,7 @@ import ShowHideProjects from './show-hide-projects';
|
||||
import TextFilterPanel from './text-filter-panel';
|
||||
import ThemePanel from './theme-panel';
|
||||
import TracingPanel from './tracing-panel';
|
||||
import { TracingAlgorithmType } from '../machines/interfaces';
|
||||
|
||||
export function Sidebar() {
|
||||
const depGraphService = useDepGraphService();
|
||||
@ -33,9 +34,8 @@ export function Sidebar() {
|
||||
const hasAffectedProjects = useDepGraphSelector(hasAffectedProjectsSelector);
|
||||
const groupByFolder = useDepGraphSelector(groupByFolderSelector);
|
||||
const collapseEdges = useDepGraphSelector(collapseEdgesSelector);
|
||||
const environment = useEnvironmentConfig();
|
||||
|
||||
const { showExperimentalFeatures } = environment.appConfig;
|
||||
const isTracing = depGraphService.state.matches('tracing');
|
||||
|
||||
// const isTracing = depGraphService.state.matches('tracing');
|
||||
const tracingInfo = useDepGraphSelector(getTracingInfo);
|
||||
@ -98,6 +98,10 @@ export function Sidebar() {
|
||||
depGraphService.send({ type: 'clearTraceEnd' });
|
||||
}
|
||||
|
||||
function setAlgorithm(algorithm: TracingAlgorithmType) {
|
||||
depGraphService.send({ type: 'setTracingAlgorithm', algorithm: algorithm });
|
||||
}
|
||||
|
||||
const updateTextFilter = useCallback(
|
||||
(textFilter: string) => {
|
||||
depGraphService.send({ type: 'filterByText', search: textFilter });
|
||||
@ -153,15 +157,16 @@ export function Sidebar() {
|
||||
resetFocus={resetFocus}
|
||||
></FocusedProjectPanel>
|
||||
) : null}
|
||||
|
||||
<ExperimentalFeature>
|
||||
{isTracing ? (
|
||||
<TracingPanel
|
||||
start={tracingInfo.start}
|
||||
end={tracingInfo.end}
|
||||
algorithm={tracingInfo.algorithm}
|
||||
setAlgorithm={setAlgorithm}
|
||||
resetStart={resetTraceStart}
|
||||
resetEnd={resetTraceEnd}
|
||||
></TracingPanel>
|
||||
</ExperimentalFeature>
|
||||
) : null}
|
||||
|
||||
<TextFilterPanel
|
||||
includePath={includePath}
|
||||
|
||||
@ -5,22 +5,55 @@ import {
|
||||
XCircleIcon,
|
||||
} from '@heroicons/react/solid';
|
||||
import { memo } from 'react';
|
||||
import { TracingAlgorithmType } from '../machines/interfaces';
|
||||
|
||||
export interface TracingPanelProps {
|
||||
start: string;
|
||||
end: string;
|
||||
algorithm: TracingAlgorithmType;
|
||||
resetStart: () => void;
|
||||
resetEnd: () => void;
|
||||
setAlgorithm: (algorithm: TracingAlgorithmType) => void;
|
||||
}
|
||||
|
||||
export const TracingPanel = memo(
|
||||
({ start, end, resetStart, resetEnd }: TracingPanelProps) => {
|
||||
({
|
||||
start,
|
||||
end,
|
||||
algorithm,
|
||||
setAlgorithm,
|
||||
resetStart,
|
||||
resetEnd,
|
||||
}: TracingPanelProps) => {
|
||||
return (
|
||||
<div className="mt-10 px-4">
|
||||
<div className="transition duration-200 ease-in-out group-hover:opacity-60">
|
||||
<h3 className="cursor-text pb-2 text-sm font-semibold uppercase tracking-wide text-slate-800 dark:text-slate-200 lg:text-xs">
|
||||
Tracing Path
|
||||
</h3>
|
||||
<div className="mb-3 flex cursor-pointer flex-row rounded-md border text-center text-xs dark:border-slate-600">
|
||||
<button
|
||||
onClick={() => setAlgorithm('shortest')}
|
||||
className={`${
|
||||
algorithm === 'shortest'
|
||||
? 'border-blue-nx-base dark:border-slate-200'
|
||||
: 'border-gray-300 dark:border-slate-600'
|
||||
} flex-1 rounded-l-md border bg-slate-50 py-2 px-4 text-slate-500 hover:bg-slate-100 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700`}
|
||||
>
|
||||
<span>Shortest</span>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setAlgorithm('all')}
|
||||
className={`${
|
||||
algorithm === 'all'
|
||||
? 'border-blue-nx-base dark:border-slate-200'
|
||||
: 'border-gray-300 dark:border-slate-600'
|
||||
} flex-1 rounded-r-md border bg-slate-50 py-2 px-4 text-slate-500 hover:bg-slate-100 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700`}
|
||||
>
|
||||
<span>All</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row items-center truncate ">
|
||||
<LocationMarkerIcon className="mr-2 h-5 w-5 text-slate-500 dark:text-slate-400" />
|
||||
{start ? (
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user