chore(graph): remove route listener and setter machines (#13524)
This commit is contained in:
parent
84cbcb7e10
commit
f1f7ccc25e
@ -1,26 +1,3 @@
|
|||||||
import {
|
|
||||||
getCheckedProjectItems,
|
|
||||||
getDeselectAllButton,
|
|
||||||
getFocusButtonForProject,
|
|
||||||
getGroupByFolderCheckbox,
|
|
||||||
getImageDownloadButton,
|
|
||||||
getIncludeProjectsInPathButton,
|
|
||||||
getSearchDepthCheckbox,
|
|
||||||
getSearchDepthIncrementButton,
|
|
||||||
getSelectAffectedButton,
|
|
||||||
getSelectAllButton,
|
|
||||||
getSelectProjectsMessage,
|
|
||||||
getTextFilterInput,
|
|
||||||
getTextFilterReset,
|
|
||||||
getToggleAllButtonForFolder,
|
|
||||||
getUncheckedProjectItems,
|
|
||||||
getUnfocusProjectButton,
|
|
||||||
} from '../support/app.po';
|
|
||||||
|
|
||||||
import * as affectedJson from '../fixtures/affected.json';
|
|
||||||
import { testProjectsRoutes } from '../support/routing-tests';
|
|
||||||
import * as nxExamplesJson from '../fixtures/nx-examples-project-graph.json';
|
|
||||||
|
|
||||||
describe('dev mode - app', () => {
|
describe('dev mode - app', () => {
|
||||||
before(() => {
|
before(() => {
|
||||||
cy.intercept('/assets/project-graphs/e2e.json', {
|
cy.intercept('/assets/project-graphs/e2e.json', {
|
||||||
|
|||||||
@ -215,6 +215,7 @@ describe('dev mode - project graph', () => {
|
|||||||
.map((dependencies) => dependencies.target)
|
.map((dependencies) => dependencies.target)
|
||||||
.includes('cart')
|
.includes('cart')
|
||||||
);
|
);
|
||||||
|
getUnfocusProjectButton().should('exist');
|
||||||
getCheckedProjectItems().should(
|
getCheckedProjectItems().should(
|
||||||
'have.length',
|
'have.length',
|
||||||
['cart', ...dependencies, ...dependents].length
|
['cart', ...dependencies, ...dependents].length
|
||||||
@ -226,6 +227,7 @@ describe('dev mode - project graph', () => {
|
|||||||
it('should uncheck all project items', () => {
|
it('should uncheck all project items', () => {
|
||||||
getFocusButtonForProject('cart').click({ force: true });
|
getFocusButtonForProject('cart').click({ force: true });
|
||||||
getUnfocusProjectButton().click();
|
getUnfocusProjectButton().click();
|
||||||
|
getUnfocusProjectButton().should('not.exist');
|
||||||
|
|
||||||
getCheckedProjectItems().should('have.length', 0);
|
getCheckedProjectItems().should('have.length', 0);
|
||||||
});
|
});
|
||||||
@ -274,34 +276,52 @@ describe('dev mode - project graph', () => {
|
|||||||
it('should set focused project', () => {
|
it('should set focused project', () => {
|
||||||
cy.contains('cart').scrollIntoView().should('be.visible');
|
cy.contains('cart').scrollIntoView().should('be.visible');
|
||||||
getFocusButtonForProject('cart').click({ force: true });
|
getFocusButtonForProject('cart').click({ force: true });
|
||||||
|
getUnfocusProjectButton().should('exist');
|
||||||
cy.url().should('contain', 'focus=cart');
|
cy.url().should('contain', '/projects/cart');
|
||||||
|
cy.reload();
|
||||||
|
getUnfocusProjectButton().should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set group by folder', () => {
|
it('should set group by folder', () => {
|
||||||
getGroupByFolderCheckbox().click();
|
getGroupByFolderCheckbox().click();
|
||||||
|
getGroupByFolderCheckbox().should('be.checked');
|
||||||
cy.url().should('contain', 'groupByFolder=true');
|
cy.url().should('contain', 'groupByFolder=true');
|
||||||
|
cy.reload();
|
||||||
|
getGroupByFolderCheckbox().should('be.checked');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set search depth disabled', () => {
|
it('should set search depth disabled', () => {
|
||||||
// it's on by default, clicking should disable it
|
// it's on by default, clicking should disable it
|
||||||
getSearchDepthCheckbox().click();
|
getSearchDepthCheckbox().click();
|
||||||
|
getSearchDepthCheckbox().should('not.be.checked');
|
||||||
cy.url().should('contain', 'searchDepth=0');
|
cy.url().should('contain', 'searchDepth=0');
|
||||||
|
cy.reload();
|
||||||
|
getSearchDepthCheckbox().should('not.be.checked');
|
||||||
|
// re-enable to clean-up for following tests
|
||||||
|
getSearchDepthCheckbox().click();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set search depth if greater than 1', () => {
|
it('should set search depth if greater than 1', () => {
|
||||||
// it's on by default and set to 1, clicking should change it to 2
|
// it's on by default and set to 1, clicking should change it to 2
|
||||||
getSearchDepthIncrementButton().click();
|
getSearchDepthIncrementButton().click();
|
||||||
|
cy.get('[data-cy="depth-value"]').should('contain', '2');
|
||||||
cy.url().should('contain', 'searchDepth=2');
|
cy.url().should('contain', 'searchDepth=2');
|
||||||
|
cy.reload();
|
||||||
|
cy.get('[data-cy="depth-value"]').should('contain', '2');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set select to all', () => {
|
it('should set select to all', () => {
|
||||||
getSelectAllButton().click();
|
getSelectAllButton().click();
|
||||||
|
getCheckedProjectItems().should(
|
||||||
cy.url().should('contain', 'select=all');
|
'have.length',
|
||||||
|
nxExamplesJson.projects.length
|
||||||
|
);
|
||||||
|
cy.url().should('contain', '/projects/all');
|
||||||
|
cy.reload();
|
||||||
|
getCheckedProjectItems().should(
|
||||||
|
'have.length',
|
||||||
|
nxExamplesJson.projects.length
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -313,7 +333,5 @@ describe('loading graph client with url params', () => {
|
|||||||
}).as('getGraph');
|
}).as('getGraph');
|
||||||
});
|
});
|
||||||
|
|
||||||
// check that params work from old base url of /
|
testProjectsRoutes('browser', ['/e2e/projects']);
|
||||||
// and also new /projects route
|
|
||||||
testProjectsRoutes('browser', ['/', '/e2e/projects']);
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,23 +1,25 @@
|
|||||||
import { testProjectsRoutes, testTaskRoutes } from '../support/routing-tests';
|
import { testProjectsRoutes, testTaskRoutes } from '../support/routing-tests';
|
||||||
|
|
||||||
describe('release static-mode app', () => {
|
describe('release static-mode app', () => {
|
||||||
beforeEach(() => {
|
describe('smoke tests', () => {
|
||||||
cy.visit('/');
|
beforeEach(() => {
|
||||||
});
|
cy.visit('/');
|
||||||
|
});
|
||||||
|
|
||||||
it('should not display experimental features', () => {
|
it('should not display experimental features', () => {
|
||||||
cy.get('experimental-features').should('not.exist');
|
cy.get('experimental-features').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not display the debugger', () => {
|
it('should not display the debugger', () => {
|
||||||
cy.get('debugger-panel').should('not.exist');
|
cy.get('debugger-panel').should('not.exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('routing', () => {
|
|
||||||
it('should use hash router', () => {
|
it('should use hash router', () => {
|
||||||
cy.url().should('contain', '/#/projects');
|
cy.url().should('contain', '/#/projects');
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
testProjectsRoutes('hash', ['/', '/projects']);
|
describe('routing', () => {
|
||||||
|
testProjectsRoutes('hash', ['/projects']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -25,7 +25,7 @@ function resolveProjectsRoute(
|
|||||||
paramString: string
|
paramString: string
|
||||||
) {
|
) {
|
||||||
if (router === 'hash') {
|
if (router === 'hash') {
|
||||||
return `/?${paramString}#${route}`;
|
return `/#${route}?${paramString}`;
|
||||||
} else {
|
} else {
|
||||||
return `${route}?${paramString}`;
|
return `${route}?${paramString}`;
|
||||||
}
|
}
|
||||||
@ -50,7 +50,7 @@ export function testProjectsRoutes(
|
|||||||
routes.forEach((route) => {
|
routes.forEach((route) => {
|
||||||
describe(`for route ${route}`, () => {
|
describe(`for route ${route}`, () => {
|
||||||
it('should focus projects', () => {
|
it('should focus projects', () => {
|
||||||
cy.visit(resolveProjectsRoute(router, route, 'focus=cart'));
|
cy.visit(resolveProjectsRoute(router, `${route}/cart`, ''));
|
||||||
|
|
||||||
// wait for first graph to finish loading
|
// wait for first graph to finish loading
|
||||||
waitForProjectGraph(router);
|
waitForProjectGraph(router);
|
||||||
@ -70,7 +70,7 @@ export function testProjectsRoutes(
|
|||||||
|
|
||||||
it('should focus projects with search depth', () => {
|
it('should focus projects with search depth', () => {
|
||||||
cy.visit(
|
cy.visit(
|
||||||
resolveProjectsRoute(router, route, `focus=cart&searchDepth=2`)
|
resolveProjectsRoute(router, `${route}/cart`, `searchDepth=2`)
|
||||||
);
|
);
|
||||||
|
|
||||||
// wait for first graph to finish loading
|
// wait for first graph to finish loading
|
||||||
@ -82,7 +82,7 @@ export function testProjectsRoutes(
|
|||||||
|
|
||||||
it('should focus projects with search depth disabled', () => {
|
it('should focus projects with search depth disabled', () => {
|
||||||
cy.visit(
|
cy.visit(
|
||||||
resolveProjectsRoute(router, route, `focus=cart&searchDepth=0`)
|
resolveProjectsRoute(router, `${route}/cart`, `searchDepth=0`)
|
||||||
);
|
);
|
||||||
|
|
||||||
// wait for first graph to finish loading
|
// wait for first graph to finish loading
|
||||||
@ -94,11 +94,7 @@ export function testProjectsRoutes(
|
|||||||
|
|
||||||
it('should set group by folder', () => {
|
it('should set group by folder', () => {
|
||||||
cy.visit(
|
cy.visit(
|
||||||
resolveProjectsRoute(
|
resolveProjectsRoute(router, `${route}/cart`, `groupByFolder=true`)
|
||||||
router,
|
|
||||||
route,
|
|
||||||
`focus=nx-dev&searchDepth=1&groupByFolder=true`
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// wait for first graph to finish loading
|
// wait for first graph to finish loading
|
||||||
@ -108,7 +104,7 @@ export function testProjectsRoutes(
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should select all projects', () => {
|
it('should select all projects', () => {
|
||||||
cy.visit(resolveProjectsRoute(router, route, `select=all`));
|
cy.visit(resolveProjectsRoute(router, `${route}/all`, ``));
|
||||||
|
|
||||||
// wait for first graph to finish loading
|
// wait for first graph to finish loading
|
||||||
waitForProjectGraph(router);
|
waitForProjectGraph(router);
|
||||||
|
|||||||
@ -3,12 +3,6 @@ import { actions, send } from 'xstate';
|
|||||||
import { ProjectGraphStateNodeConfig } from './interfaces';
|
import { ProjectGraphStateNodeConfig } from './interfaces';
|
||||||
|
|
||||||
export const customSelectedStateConfig: ProjectGraphStateNodeConfig = {
|
export const customSelectedStateConfig: ProjectGraphStateNodeConfig = {
|
||||||
entry: actions.choose([
|
|
||||||
{
|
|
||||||
cond: 'selectActionCannotBePersistedToRoute',
|
|
||||||
actions: ['notifyRouteClearSelect'],
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
on: {
|
on: {
|
||||||
updateGraph: {
|
updateGraph: {
|
||||||
target: 'customSelected',
|
target: 'customSelected',
|
||||||
|
|||||||
@ -9,59 +9,28 @@ export const focusedStateConfig: ProjectGraphStateNodeConfig = {
|
|||||||
|
|
||||||
ctx.focusedProject = event.projectName;
|
ctx.focusedProject = event.projectName;
|
||||||
}),
|
}),
|
||||||
send(
|
|
||||||
(ctx, event) => {
|
|
||||||
if (event.type !== 'focusProject') return;
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'notifyRouteFocusProject',
|
|
||||||
focusedProject: event.projectName,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: (context) => context.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
'notifyGraphFocusProject',
|
'notifyGraphFocusProject',
|
||||||
],
|
],
|
||||||
exit: [
|
exit: [
|
||||||
assign((ctx) => {
|
assign((ctx) => {
|
||||||
ctx.focusedProject = null;
|
ctx.focusedProject = null;
|
||||||
}),
|
}),
|
||||||
'notifyRouteUnfocusProject',
|
|
||||||
],
|
],
|
||||||
on: {
|
on: {
|
||||||
incrementSearchDepth: {
|
incrementSearchDepth: {
|
||||||
actions: [
|
actions: ['incrementSearchDepth', 'notifyGraphFocusProject'],
|
||||||
'incrementSearchDepth',
|
|
||||||
'notifyGraphFocusProject',
|
|
||||||
'notifyRouteSearchDepth',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
decrementSearchDepth: {
|
decrementSearchDepth: {
|
||||||
actions: [
|
actions: ['decrementSearchDepth', 'notifyGraphFocusProject'],
|
||||||
'decrementSearchDepth',
|
|
||||||
'notifyGraphFocusProject',
|
|
||||||
'notifyRouteSearchDepth',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
setSearchDepthEnabled: {
|
setSearchDepthEnabled: {
|
||||||
actions: [
|
actions: ['setSearchDepthEnabled', 'notifyGraphFocusProject'],
|
||||||
'setSearchDepthEnabled',
|
|
||||||
'notifyGraphFocusProject',
|
|
||||||
'notifyRouteSearchDepth',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
setSearchDepth: {
|
setSearchDepth: {
|
||||||
actions: [
|
actions: ['setSearchDepth', 'notifyGraphFocusProject'],
|
||||||
'setSearchDepth',
|
|
||||||
'notifyGraphFocusProject',
|
|
||||||
'notifyRouteSearchDepth',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
unfocusProject: {
|
unfocusProject: {
|
||||||
target: 'unselected',
|
target: 'unselected',
|
||||||
actions: ['notifyRouteUnfocusProject'],
|
|
||||||
},
|
},
|
||||||
updateGraph: {
|
updateGraph: {
|
||||||
actions: [
|
actions: [
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
ProjectGraphProjectNode,
|
ProjectGraphProjectNode,
|
||||||
} from 'nx/src/config/project-graph';
|
} from 'nx/src/config/project-graph';
|
||||||
import { ActionObject, ActorRef, State, StateNodeConfig } from 'xstate';
|
import { ActionObject, ActorRef, State, StateNodeConfig } from 'xstate';
|
||||||
import { GraphRenderEvents, RouteEvents } from '../../machines/interfaces';
|
import { GraphRenderEvents } from '../../machines/interfaces';
|
||||||
|
|
||||||
// The hierarchical schema for the states
|
// The hierarchical schema for the states
|
||||||
export interface ProjectGraphSchema {
|
export interface ProjectGraphSchema {
|
||||||
@ -85,8 +85,6 @@ export interface ProjectGraphContext {
|
|||||||
appsDir: string;
|
appsDir: string;
|
||||||
};
|
};
|
||||||
graphActor: ActorRef<GraphRenderEvents>;
|
graphActor: ActorRef<GraphRenderEvents>;
|
||||||
routeSetterActor: ActorRef<RouteEvents>;
|
|
||||||
routeListenerActor: ActorRef<ProjectGraphMachineEvents>;
|
|
||||||
lastPerfReport: GraphPerfReport;
|
lastPerfReport: GraphPerfReport;
|
||||||
tracing: {
|
tracing: {
|
||||||
start: string;
|
start: string;
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { createMachine, send, spawn } from 'xstate';
|
|||||||
import { customSelectedStateConfig } from './custom-selected.state';
|
import { customSelectedStateConfig } from './custom-selected.state';
|
||||||
import { focusedStateConfig } from './focused.state';
|
import { focusedStateConfig } from './focused.state';
|
||||||
import { graphActor } from './graph.actor';
|
import { graphActor } from './graph.actor';
|
||||||
import { createRouteMachine } from '../../machines/route-setter.machine';
|
|
||||||
import { textFilteredStateConfig } from './text-filtered.state';
|
import { textFilteredStateConfig } from './text-filtered.state';
|
||||||
import { tracingStateConfig } from './tracing.state';
|
import { tracingStateConfig } from './tracing.state';
|
||||||
import { unselectedStateConfig } from './unselected.state';
|
import { unselectedStateConfig } from './unselected.state';
|
||||||
@ -26,8 +25,6 @@ export const initialContext: ProjectGraphContext = {
|
|||||||
appsDir: '',
|
appsDir: '',
|
||||||
},
|
},
|
||||||
graphActor: null,
|
graphActor: null,
|
||||||
routeSetterActor: null,
|
|
||||||
routeListenerActor: null,
|
|
||||||
lastPerfReport: {
|
lastPerfReport: {
|
||||||
numEdges: 0,
|
numEdges: 0,
|
||||||
numNodes: 0,
|
numNodes: 0,
|
||||||
@ -96,14 +93,11 @@ export const projectGraphMachine = createMachine<
|
|||||||
},
|
},
|
||||||
selectAll: {
|
selectAll: {
|
||||||
target: 'customSelected',
|
target: 'customSelected',
|
||||||
actions: ['notifyGraphShowAllProjects', 'notifyRouteSelectAll'],
|
actions: ['notifyGraphShowAllProjects'],
|
||||||
},
|
},
|
||||||
selectAffected: {
|
selectAffected: {
|
||||||
target: 'customSelected',
|
target: 'customSelected',
|
||||||
actions: [
|
actions: ['notifyGraphShowAffectedProjects'],
|
||||||
'notifyGraphShowAffectedProjects',
|
|
||||||
'notifyRouteSelectAffected',
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
deselectProject: [
|
deselectProject: [
|
||||||
{
|
{
|
||||||
@ -155,19 +149,6 @@ export const projectGraphMachine = createMachine<
|
|||||||
to: (context) => context.graphActor,
|
to: (context) => context.graphActor,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
send(
|
|
||||||
(ctx, event) => {
|
|
||||||
if (event.type !== 'setCollapseEdges') return;
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'notifyRouteCollapseEdges',
|
|
||||||
collapseEdges: event.collapseEdges,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: (context) => context.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
setGroupByFolder: {
|
setGroupByFolder: {
|
||||||
@ -188,19 +169,6 @@ export const projectGraphMachine = createMachine<
|
|||||||
to: (context) => context.graphActor,
|
to: (context) => context.graphActor,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
send(
|
|
||||||
(ctx, event) => {
|
|
||||||
if (event.type !== 'setGroupByFolder') return;
|
|
||||||
|
|
||||||
return {
|
|
||||||
type: 'notifyRouteGroupByFolder',
|
|
||||||
groupByFolder: event.groupByFolder,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: (context) => context.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
setIncludeProjectsByPath: {
|
setIncludeProjectsByPath: {
|
||||||
@ -211,23 +179,22 @@ export const projectGraphMachine = createMachine<
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
incrementSearchDepth: {
|
incrementSearchDepth: {
|
||||||
actions: ['incrementSearchDepth', 'notifyRouteSearchDepth'],
|
actions: ['incrementSearchDepth'],
|
||||||
},
|
},
|
||||||
decrementSearchDepth: {
|
decrementSearchDepth: {
|
||||||
actions: ['decrementSearchDepth', 'notifyRouteSearchDepth'],
|
actions: ['decrementSearchDepth'],
|
||||||
},
|
},
|
||||||
setSearchDepthEnabled: {
|
setSearchDepthEnabled: {
|
||||||
actions: ['setSearchDepthEnabled', 'notifyRouteSearchDepth'],
|
actions: ['setSearchDepthEnabled'],
|
||||||
},
|
},
|
||||||
setSearchDepth: {
|
setSearchDepth: {
|
||||||
actions: ['setSearchDepth', 'notifyRouteSearchDepth'],
|
actions: ['setSearchDepth'],
|
||||||
},
|
},
|
||||||
setTracingAlgorithm: {
|
setTracingAlgorithm: {
|
||||||
actions: [
|
actions: [
|
||||||
assign((ctx, event) => {
|
assign((ctx, event) => {
|
||||||
ctx.tracing.algorithm = event.algorithm;
|
ctx.tracing.algorithm = event.algorithm;
|
||||||
}),
|
}),
|
||||||
'notifyRouteTracing',
|
|
||||||
'notifyGraphTracing',
|
'notifyGraphTracing',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -241,9 +208,6 @@ export const projectGraphMachine = createMachine<
|
|||||||
deselectLastProject: (ctx) => {
|
deselectLastProject: (ctx) => {
|
||||||
return ctx.selectedProjects.length <= 1;
|
return ctx.selectedProjects.length <= 1;
|
||||||
},
|
},
|
||||||
selectActionCannotBePersistedToRoute: (ctx, event) => {
|
|
||||||
return event.type !== 'selectAffected' && event.type !== 'selectAll';
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
setGroupByFolder: assign((ctx, event) => {
|
setGroupByFolder: assign((ctx, event) => {
|
||||||
@ -286,9 +250,9 @@ export const projectGraphMachine = createMachine<
|
|||||||
ctx.projects = event.projects;
|
ctx.projects = event.projects;
|
||||||
ctx.dependencies = event.dependencies;
|
ctx.dependencies = event.dependencies;
|
||||||
ctx.graphActor = spawn(graphActor, 'graphActor');
|
ctx.graphActor = spawn(graphActor, 'graphActor');
|
||||||
ctx.routeSetterActor = spawn(createRouteMachine(), {
|
// ctx.routeSetterActor = spawn(createRouteMachine(), {
|
||||||
name: 'route',
|
// name: 'route',
|
||||||
});
|
// });
|
||||||
|
|
||||||
if (event.type === 'setProjects') {
|
if (event.type === 'setProjects') {
|
||||||
ctx.workspaceLayout = event.workspaceLayout;
|
ctx.workspaceLayout = event.workspaceLayout;
|
||||||
@ -388,62 +352,7 @@ export const projectGraphMachine = createMachine<
|
|||||||
to: (context) => context.graphActor,
|
to: (context) => context.graphActor,
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
notifyRouteUnfocusProject: send(
|
|
||||||
() => ({
|
|
||||||
type: 'notifyRouteUnfocusProject',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
to: (ctx) => ctx.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
notifyRouteSelectAll: send(
|
|
||||||
() => ({
|
|
||||||
type: 'notifyRouteSelectAll',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
to: (ctx) => ctx.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
notifyRouteSelectAffected: send(
|
|
||||||
() => ({
|
|
||||||
type: 'notifyRouteSelectAffected',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
to: (ctx) => ctx.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
notifyRouteClearSelect: send(
|
|
||||||
() => ({
|
|
||||||
type: 'notifyRouteClearSelect',
|
|
||||||
}),
|
|
||||||
{
|
|
||||||
to: (ctx) => ctx.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
notifyRouteTracing: send(
|
|
||||||
(ctx) => {
|
|
||||||
return {
|
|
||||||
type: 'notifyRouteTracing',
|
|
||||||
start: ctx.tracing.start,
|
|
||||||
end: ctx.tracing.end,
|
|
||||||
algorithm: ctx.tracing.algorithm,
|
|
||||||
};
|
|
||||||
},
|
|
||||||
{
|
|
||||||
to: (ctx) => ctx.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
notifyRouteSearchDepth: send(
|
|
||||||
(ctx, event) => ({
|
|
||||||
type: 'notifyRouteSearchDepth',
|
|
||||||
searchDepth: ctx.searchDepth,
|
|
||||||
searchDepthEnabled: ctx.searchDepthEnabled,
|
|
||||||
}),
|
|
||||||
|
|
||||||
{
|
|
||||||
to: (ctx) => ctx.routeSetterActor,
|
|
||||||
}
|
|
||||||
),
|
|
||||||
notifyGraphFilterProjectsByText: send(
|
notifyGraphFilterProjectsByText: send(
|
||||||
(context, event) => ({
|
(context, event) => ({
|
||||||
type: 'notifyGraphFilterProjectsByText',
|
type: 'notifyGraphFilterProjectsByText',
|
||||||
|
|||||||
@ -10,7 +10,6 @@ export const tracingStateConfig: ProjectGraphStateNodeConfig = {
|
|||||||
ctx.tracing.end = event.projectName;
|
ctx.tracing.end = event.projectName;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
'notifyRouteTracing',
|
|
||||||
'notifyGraphTracing',
|
'notifyGraphTracing',
|
||||||
],
|
],
|
||||||
exit: [
|
exit: [
|
||||||
@ -20,7 +19,6 @@ export const tracingStateConfig: ProjectGraphStateNodeConfig = {
|
|||||||
ctx.tracing.end = null;
|
ctx.tracing.end = null;
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
'notifyRouteTracing',
|
|
||||||
],
|
],
|
||||||
on: {
|
on: {
|
||||||
clearTraceStart: {
|
clearTraceStart: {
|
||||||
@ -28,7 +26,6 @@ export const tracingStateConfig: ProjectGraphStateNodeConfig = {
|
|||||||
assign((ctx) => {
|
assign((ctx) => {
|
||||||
ctx.tracing.start = null;
|
ctx.tracing.start = null;
|
||||||
}),
|
}),
|
||||||
'notifyRouteTracing',
|
|
||||||
'notifyGraphTracing',
|
'notifyGraphTracing',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -37,7 +34,6 @@ export const tracingStateConfig: ProjectGraphStateNodeConfig = {
|
|||||||
assign((ctx) => {
|
assign((ctx) => {
|
||||||
ctx.tracing.end = null;
|
ctx.tracing.end = null;
|
||||||
}),
|
}),
|
||||||
'notifyRouteTracing',
|
|
||||||
'notifyGraphTracing',
|
'notifyGraphTracing',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,18 +1,9 @@
|
|||||||
import { assign } from '@xstate/immer';
|
import { assign } from '@xstate/immer';
|
||||||
import { send, spawn } from 'xstate';
|
import { send } from 'xstate';
|
||||||
import { routeListener } from '../../machines/route-listener.actor';
|
|
||||||
import { ProjectGraphStateNodeConfig } from './interfaces';
|
import { ProjectGraphStateNodeConfig } from './interfaces';
|
||||||
|
|
||||||
export const unselectedStateConfig: ProjectGraphStateNodeConfig = {
|
export const unselectedStateConfig: ProjectGraphStateNodeConfig = {
|
||||||
entry: [
|
entry: ['notifyGraphHideAllProjects'],
|
||||||
'notifyGraphHideAllProjects',
|
|
||||||
assign((ctx, event) => {
|
|
||||||
if (ctx.routeListenerActor === null) {
|
|
||||||
ctx.routeListenerActor = spawn(routeListener, 'routeListener');
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
'notifyRouteClearSelect',
|
|
||||||
],
|
|
||||||
on: {
|
on: {
|
||||||
updateGraph: {
|
updateGraph: {
|
||||||
target: 'customSelected',
|
target: 'customSelected',
|
||||||
|
|||||||
@ -57,6 +57,7 @@ export const SearchDepth = memo(
|
|||||||
</button>
|
</button>
|
||||||
<span
|
<span
|
||||||
id="depthFilterValue"
|
id="depthFilterValue"
|
||||||
|
data-cy="depth-value"
|
||||||
className="block w-full flex-1 rounded-none border-t border-b border-slate-300 bg-white p-1.5 text-center font-mono dark:border-slate-600 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700"
|
className="block w-full flex-1 rounded-none border-t border-b border-slate-300 bg-white p-1.5 text-center font-mono dark:border-slate-600 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700"
|
||||||
>
|
>
|
||||||
{searchDepth}
|
{searchDepth}
|
||||||
|
|||||||
@ -13,10 +13,15 @@ import {
|
|||||||
selectedProjectNamesSelector,
|
selectedProjectNamesSelector,
|
||||||
workspaceLayoutSelector,
|
workspaceLayoutSelector,
|
||||||
} from './machines/selectors';
|
} from './machines/selectors';
|
||||||
import { getProjectsByType, parseParentDirectoriesFromFilePath } from '../util';
|
import {
|
||||||
|
getProjectsByType,
|
||||||
|
parseParentDirectoriesFromFilePath,
|
||||||
|
useRouteConstructor,
|
||||||
|
} from '../util';
|
||||||
import ExperimentalFeature from '../ui-components/experimental-feature';
|
import ExperimentalFeature from '../ui-components/experimental-feature';
|
||||||
import { TracingAlgorithmType } from './machines/interfaces';
|
import { TracingAlgorithmType } from './machines/interfaces';
|
||||||
import { getProjectGraphService } from '../machines/get-services';
|
import { getProjectGraphService } from '../machines/get-services';
|
||||||
|
import { Link, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
interface SidebarProject {
|
interface SidebarProject {
|
||||||
projectGraphNode: ProjectGraphNode;
|
projectGraphNode: ProjectGraphNode;
|
||||||
@ -70,6 +75,8 @@ function ProjectListItem({
|
|||||||
tracingInfo: TracingInfo;
|
tracingInfo: TracingInfo;
|
||||||
}) {
|
}) {
|
||||||
const projectGraphService = getProjectGraphService();
|
const projectGraphService = getProjectGraphService();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const routeConstructor = useRouteConstructor();
|
||||||
|
|
||||||
function startTrace(projectName: string) {
|
function startTrace(projectName: string) {
|
||||||
projectGraphService.send({ type: 'setTracingStart', projectName });
|
projectGraphService.send({ type: 'setTracingStart', projectName });
|
||||||
@ -85,24 +92,23 @@ function ProjectListItem({
|
|||||||
} else {
|
} else {
|
||||||
projectGraphService.send({ type: 'selectProject', projectName });
|
projectGraphService.send({ type: 'selectProject', projectName });
|
||||||
}
|
}
|
||||||
}
|
navigate(routeConstructor('/projects', true));
|
||||||
|
|
||||||
function focusProject(projectName: string) {
|
|
||||||
projectGraphService.send({ type: 'focusProject', projectName });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li className="relative block cursor-default select-none py-1 pl-2 pr-6 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">
|
<div className="flex items-center">
|
||||||
<button
|
<Link
|
||||||
data-cy={`focus-button-${project.projectGraphNode.name}`}
|
data-cy={`focus-button-${project.projectGraphNode.name}`}
|
||||||
type="button"
|
|
||||||
className="mr-1 flex items-center rounded-md border-slate-300 bg-white p-1 font-medium text-slate-500 shadow-sm ring-1 ring-slate-200 transition hover:bg-slate-50 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-400 dark:ring-slate-600 hover:dark:bg-slate-700"
|
className="mr-1 flex items-center rounded-md border-slate-300 bg-white p-1 font-medium text-slate-500 shadow-sm ring-1 ring-slate-200 transition hover:bg-slate-50 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-400 dark:ring-slate-600 hover:dark:bg-slate-700"
|
||||||
title="Focus on this library"
|
title="Focus on this library"
|
||||||
onClick={() => focusProject(project.projectGraphNode.name)}
|
to={routeConstructor(
|
||||||
|
`/projects/${project.projectGraphNode.name}`,
|
||||||
|
true
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<DocumentMagnifyingGlassIcon className="h-5 w-5" />
|
<DocumentMagnifyingGlassIcon className="h-5 w-5" />
|
||||||
</button>
|
</Link>
|
||||||
|
|
||||||
<ExperimentalFeature>
|
<ExperimentalFeature>
|
||||||
<span className="relative z-0 inline-flex rounded-md shadow-sm">
|
<span className="relative z-0 inline-flex rounded-md shadow-sm">
|
||||||
|
|||||||
@ -25,8 +25,15 @@ import { getProjectGraphService } from '../machines/get-services';
|
|||||||
import { useIntervalWhen } from '../hooks/use-interval-when';
|
import { useIntervalWhen } from '../hooks/use-interval-when';
|
||||||
// nx-ignore-next-line
|
// nx-ignore-next-line
|
||||||
import { ProjectGraphClientResponse } from 'nx/src/command-line/dep-graph';
|
import { ProjectGraphClientResponse } from 'nx/src/command-line/dep-graph';
|
||||||
import { useParams, useRouteLoaderData } from 'react-router-dom';
|
import {
|
||||||
|
useNavigate,
|
||||||
|
useParams,
|
||||||
|
useRouteLoaderData,
|
||||||
|
useSearchParams,
|
||||||
|
} from 'react-router-dom';
|
||||||
import { getProjectGraphDataService } from '../hooks/get-project-graph-data-service';
|
import { getProjectGraphDataService } from '../hooks/get-project-graph-data-service';
|
||||||
|
import { useCurrentPath } from '../hooks/use-current-path';
|
||||||
|
import { useRouteConstructor } from '../util';
|
||||||
|
|
||||||
export function ProjectsSidebar(): JSX.Element {
|
export function ProjectsSidebar(): JSX.Element {
|
||||||
const environmentConfig = useEnvironmentConfig();
|
const environmentConfig = useEnvironmentConfig();
|
||||||
@ -41,58 +48,106 @@ export function ProjectsSidebar(): JSX.Element {
|
|||||||
const groupByFolder = useProjectGraphSelector(groupByFolderSelector);
|
const groupByFolder = useProjectGraphSelector(groupByFolderSelector);
|
||||||
const collapseEdges = useProjectGraphSelector(collapseEdgesSelector);
|
const collapseEdges = useProjectGraphSelector(collapseEdgesSelector);
|
||||||
|
|
||||||
const isTracing = projectGraphService.state.matches('tracing');
|
const isTracing = projectGraphService.getSnapshot().matches('tracing');
|
||||||
const tracingInfo = useProjectGraphSelector(getTracingInfo);
|
const tracingInfo = useProjectGraphSelector(getTracingInfo);
|
||||||
const projectGraphDataService = getProjectGraphDataService();
|
const projectGraphDataService = getProjectGraphDataService();
|
||||||
|
|
||||||
|
const routeParams = useParams();
|
||||||
|
const currentRoute = useCurrentPath();
|
||||||
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
|
|
||||||
const selectedProjectRouteData = useRouteLoaderData(
|
const selectedProjectRouteData = useRouteLoaderData(
|
||||||
'selectedWorkspace'
|
'selectedWorkspace'
|
||||||
) as ProjectGraphClientResponse;
|
) as ProjectGraphClientResponse;
|
||||||
const params = useParams();
|
const params = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const routeContructor = useRouteConstructor();
|
||||||
|
|
||||||
function resetFocus() {
|
function resetFocus() {
|
||||||
projectGraphService.send({ type: 'unfocusProject' });
|
projectGraphService.send({ type: 'unfocusProject' });
|
||||||
|
navigate(routeContructor('/projects', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAllProjects() {
|
function showAllProjects() {
|
||||||
projectGraphService.send({ type: 'selectAll' });
|
navigate(routeContructor('/projects/all', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideAllProjects() {
|
function hideAllProjects() {
|
||||||
projectGraphService.send({ type: 'deselectAll' });
|
projectGraphService.send({ type: 'deselectAll' });
|
||||||
|
navigate(routeContructor('/projects', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAffectedProjects() {
|
function showAffectedProjects() {
|
||||||
projectGraphService.send({ type: 'selectAffected' });
|
navigate(routeContructor('/projects/affected', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchDepthFilterEnabledChange(checked: boolean) {
|
function searchDepthFilterEnabledChange(checked: boolean) {
|
||||||
projectGraphService.send({
|
setSearchParams((currentSearchParams) => {
|
||||||
type: 'setSearchDepthEnabled',
|
if (checked && searchDepthInfo.searchDepth > 1) {
|
||||||
searchDepthEnabled: checked,
|
currentSearchParams.set(
|
||||||
|
'searchDepth',
|
||||||
|
searchDepthInfo.searchDepth.toString()
|
||||||
|
);
|
||||||
|
} else if (checked && searchDepthInfo.searchDepth === 1) {
|
||||||
|
currentSearchParams.delete('searchDepth');
|
||||||
|
} else {
|
||||||
|
currentSearchParams.set('searchDepth', '0');
|
||||||
|
}
|
||||||
|
return currentSearchParams;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function groupByFolderChanged(checked: boolean) {
|
function groupByFolderChanged(checked: boolean) {
|
||||||
projectGraphService.send({
|
setSearchParams((currentSearchParams) => {
|
||||||
type: 'setGroupByFolder',
|
if (checked) {
|
||||||
groupByFolder: checked,
|
currentSearchParams.set('groupByFolder', 'true');
|
||||||
|
} else {
|
||||||
|
currentSearchParams.delete('groupByFolder');
|
||||||
|
}
|
||||||
|
return currentSearchParams;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function collapseEdgesChanged(checked: boolean) {
|
function collapseEdgesChanged(checked: boolean) {
|
||||||
projectGraphService.send({
|
setSearchParams((currentSearchParams) => {
|
||||||
type: 'setCollapseEdges',
|
if (checked) {
|
||||||
collapseEdges: checked,
|
currentSearchParams.set('collapseEdges', 'true');
|
||||||
|
} else {
|
||||||
|
currentSearchParams.delete('collapseEdges');
|
||||||
|
}
|
||||||
|
return currentSearchParams;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function incrementDepthFilter() {
|
function incrementDepthFilter() {
|
||||||
projectGraphService.send({ type: 'incrementSearchDepth' });
|
if (searchDepthInfo.searchDepthEnabled) {
|
||||||
|
const newSearchDepth = searchDepthInfo.searchDepth + 1;
|
||||||
|
setSearchParams((currentSearchParams) => {
|
||||||
|
if (newSearchDepth === 1) {
|
||||||
|
currentSearchParams.delete('searchDepth');
|
||||||
|
} else {
|
||||||
|
currentSearchParams.set('searchDepth', newSearchDepth.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentSearchParams;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrementDepthFilter() {
|
function decrementDepthFilter() {
|
||||||
projectGraphService.send({ type: 'decrementSearchDepth' });
|
if (searchDepthInfo.searchDepthEnabled) {
|
||||||
|
const newSearchDepth =
|
||||||
|
searchDepthInfo.searchDepth === 0 ? 0 : searchDepthInfo.searchDepth - 1;
|
||||||
|
setSearchParams((currentSearchParams) => {
|
||||||
|
if (newSearchDepth === 1) {
|
||||||
|
currentSearchParams.delete('searchDepth');
|
||||||
|
} else {
|
||||||
|
currentSearchParams.set('searchDepth', newSearchDepth.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentSearchParams;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetTextFilter() {
|
function resetTextFilter() {
|
||||||
@ -108,16 +163,19 @@ export function ProjectsSidebar(): JSX.Element {
|
|||||||
|
|
||||||
function resetTraceStart() {
|
function resetTraceStart() {
|
||||||
projectGraphService.send({ type: 'clearTraceStart' });
|
projectGraphService.send({ type: 'clearTraceStart' });
|
||||||
|
navigate(routeContructor('/projects', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetTraceEnd() {
|
function resetTraceEnd() {
|
||||||
projectGraphService.send({ type: 'clearTraceEnd' });
|
projectGraphService.send({ type: 'clearTraceEnd' });
|
||||||
|
navigate(routeContructor('/projects', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function setAlgorithm(algorithm: TracingAlgorithmType) {
|
function setAlgorithm(algorithm: TracingAlgorithmType) {
|
||||||
projectGraphService.send({
|
setSearchParams((searchParams) => {
|
||||||
type: 'setTracingAlgorithm',
|
searchParams.set('traceAlgorithm', algorithm);
|
||||||
algorithm: algorithm,
|
|
||||||
|
return searchParams;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,6 +189,108 @@ export function ProjectsSidebar(): JSX.Element {
|
|||||||
});
|
});
|
||||||
}, [selectedProjectRouteData]);
|
}, [selectedProjectRouteData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
switch (currentRoute.currentPath) {
|
||||||
|
case '/projects/all':
|
||||||
|
projectGraphService.send({ type: 'selectAll' });
|
||||||
|
break;
|
||||||
|
case '/projects/affected':
|
||||||
|
projectGraphService.send({ type: 'selectAffected' });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}, [currentRoute]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (routeParams.focusedProject) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'focusProject',
|
||||||
|
projectName: routeParams.focusedProject,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (routeParams.startTrace) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setTracingStart',
|
||||||
|
projectName: routeParams.startTrace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (routeParams.endTrace) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setTracingEnd',
|
||||||
|
projectName: routeParams.endTrace,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [routeParams]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (searchParams.has('groupByFolder') && groupByFolder === false) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setGroupByFolder',
|
||||||
|
groupByFolder: true,
|
||||||
|
});
|
||||||
|
} else if (!searchParams.has('groupByFolder') && groupByFolder === true) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setGroupByFolder',
|
||||||
|
groupByFolder: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.has('collapseEdges') && collapseEdges === false) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setCollapseEdges',
|
||||||
|
collapseEdges: true,
|
||||||
|
});
|
||||||
|
} else if (!searchParams.has('collapseEdges') && collapseEdges === true) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setCollapseEdges',
|
||||||
|
collapseEdges: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.has('searchDepth')) {
|
||||||
|
const parsedValue = parseInt(searchParams.get('searchDepth'), 10);
|
||||||
|
|
||||||
|
if (parsedValue === 0) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setSearchDepthEnabled',
|
||||||
|
searchDepthEnabled: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setSearchDepth',
|
||||||
|
searchDepth: parsedValue,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (
|
||||||
|
searchDepthInfo.searchDepthEnabled === false ||
|
||||||
|
searchDepthInfo.searchDepth !== 1
|
||||||
|
) {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setSearchDepthEnabled',
|
||||||
|
searchDepthEnabled: true,
|
||||||
|
});
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setSearchDepth',
|
||||||
|
searchDepth: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchParams.has('traceAlgorithm')) {
|
||||||
|
const tracingAlgorithm = searchParams.get('traceAlgorithm');
|
||||||
|
if (tracingAlgorithm === 'shortest' || tracingAlgorithm === 'all') {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setTracingAlgorithm',
|
||||||
|
algorithm: tracingAlgorithm,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (tracingInfo.algorithm !== 'shortest') {
|
||||||
|
projectGraphService.send({
|
||||||
|
type: 'setTracingAlgorithm',
|
||||||
|
algorithm: 'shortest',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [searchParams]);
|
||||||
|
|
||||||
useIntervalWhen(
|
useIntervalWhen(
|
||||||
() => {
|
() => {
|
||||||
const selectedWorkspaceId =
|
const selectedWorkspaceId =
|
||||||
@ -163,6 +323,7 @@ export function ProjectsSidebar(): JSX.Element {
|
|||||||
const updateTextFilter = useCallback(
|
const updateTextFilter = useCallback(
|
||||||
(textFilter: string) => {
|
(textFilter: string) => {
|
||||||
projectGraphService.send({ type: 'filterByText', search: textFilter });
|
projectGraphService.send({ type: 'filterByText', search: textFilter });
|
||||||
|
navigate(routeContructor('/projects', true));
|
||||||
},
|
},
|
||||||
[projectGraphService]
|
[projectGraphService]
|
||||||
);
|
);
|
||||||
|
|||||||
@ -38,16 +38,16 @@ export function TasksSidebar() {
|
|||||||
const [searchParams, setSearchParams] = useSearchParams();
|
const [searchParams, setSearchParams] = useSearchParams();
|
||||||
const groupByProject = searchParams.get('groupByProject') === 'true';
|
const groupByProject = searchParams.get('groupByProject') === 'true';
|
||||||
|
|
||||||
const selectedProjectRouteData = useRouteLoaderData(
|
const selectedWorkspaceRouteData = useRouteLoaderData(
|
||||||
'selectedWorkspace'
|
'selectedWorkspace'
|
||||||
) as ProjectGraphClientResponse & { targets: string[] };
|
) as ProjectGraphClientResponse & { targets: string[] };
|
||||||
const workspaceLayout = selectedProjectRouteData.layout;
|
const workspaceLayout = selectedWorkspaceRouteData.layout;
|
||||||
|
|
||||||
const routeData = useRouteLoaderData(
|
const routeData = useRouteLoaderData(
|
||||||
'selectedTarget'
|
'selectedTarget'
|
||||||
) as TaskGraphClientResponse;
|
) as TaskGraphClientResponse;
|
||||||
const { taskGraphs } = routeData;
|
const { taskGraphs } = routeData;
|
||||||
const { projects, targets } = selectedProjectRouteData;
|
const { projects, targets } = selectedWorkspaceRouteData;
|
||||||
const selectedTarget = params['selectedTarget'] ?? targets[0];
|
const selectedTarget = params['selectedTarget'] ?? targets[0];
|
||||||
|
|
||||||
const [selectedProjects, setSelectedProjects] = useState<string[]>([]);
|
const [selectedProjects, setSelectedProjects] = useState<string[]>([]);
|
||||||
@ -131,10 +131,10 @@ export function TasksSidebar() {
|
|||||||
setSelectedProjects([]);
|
setSelectedProjects([]);
|
||||||
graphService.handleTaskEvent({
|
graphService.handleTaskEvent({
|
||||||
type: 'notifyTaskGraphSetProjects',
|
type: 'notifyTaskGraphSetProjects',
|
||||||
projects: selectedProjectRouteData.projects,
|
projects: selectedWorkspaceRouteData.projects,
|
||||||
taskGraphs,
|
taskGraphs,
|
||||||
});
|
});
|
||||||
}, [selectedProjectRouteData]);
|
}, [selectedWorkspaceRouteData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (groupByProject) {
|
if (groupByProject) {
|
||||||
|
|||||||
@ -1,20 +1,34 @@
|
|||||||
import { matchRoutes, useLocation } from 'react-router-dom';
|
import { matchRoutes, useLocation } from 'react-router-dom';
|
||||||
import { getRoutesForEnvironment } from '../routes';
|
import { getRoutesForEnvironment } from '../routes';
|
||||||
import { getEnvironmentConfig } from './use-environment-config';
|
import { getEnvironmentConfig } from './use-environment-config';
|
||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
export const useCurrentPath = () => {
|
export const useCurrentPath = () => {
|
||||||
|
const [lastLocation, setLastLocation] = useState<string>();
|
||||||
|
const [lastPath, setLastPath] = useState();
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
|
||||||
|
if (location.pathname === lastLocation) {
|
||||||
|
return lastPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLastLocation(location.pathname);
|
||||||
|
|
||||||
const route = matchRoutes(getRoutesForEnvironment(), location).at(-1);
|
const route = matchRoutes(getRoutesForEnvironment(), location).at(-1);
|
||||||
|
|
||||||
const { environment } = getEnvironmentConfig();
|
const { environment } = getEnvironmentConfig();
|
||||||
|
|
||||||
|
let currentPath;
|
||||||
// if using dev routes, remove first segment for workspace
|
// if using dev routes, remove first segment for workspace
|
||||||
if (environment === 'dev') {
|
if (environment === 'dev') {
|
||||||
return {
|
currentPath = {
|
||||||
workspace: route.pathname.split('/')[1],
|
workspace: route.pathname.split('/')[1],
|
||||||
currentPath: `/${route.pathname.split('/').slice(2).join('/')}`,
|
currentPath: `/${route.pathname.split('/').slice(2).join('/')}`,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
return { workspace: 'local', currentPath: route.pathname };
|
currentPath = { workspace: 'local', currentPath: route.pathname };
|
||||||
}
|
}
|
||||||
|
setLastPath(currentPath);
|
||||||
|
return currentPath;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -66,38 +66,3 @@ export type GraphRenderEvents =
|
|||||||
end: string;
|
end: string;
|
||||||
algorithm: TracingAlgorithmType;
|
algorithm: TracingAlgorithmType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RouteEvents =
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteFocusProject';
|
|
||||||
focusedProject: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteGroupByFolder';
|
|
||||||
groupByFolder: boolean;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteCollapseEdges';
|
|
||||||
collapseEdges: boolean;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteSearchDepth';
|
|
||||||
searchDepthEnabled: boolean;
|
|
||||||
searchDepth: number;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteUnfocusProject';
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteSelectAll';
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteSelectAffected';
|
|
||||||
}
|
|
||||||
| { type: 'notifyRouteClearSelect' }
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteTracing';
|
|
||||||
start: string;
|
|
||||||
end: string;
|
|
||||||
algorithm: TracingAlgorithmType;
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,73 +0,0 @@
|
|||||||
import { createBrowserHistory } from 'history';
|
|
||||||
import { InvokeCallback } from 'xstate';
|
|
||||||
import { ProjectGraphMachineEvents } from '../feature-projects/machines/interfaces';
|
|
||||||
|
|
||||||
function parseSearchParamsToEvents(
|
|
||||||
searchParams: string
|
|
||||||
): ProjectGraphMachineEvents[] {
|
|
||||||
const events: ProjectGraphMachineEvents[] = [];
|
|
||||||
const params = new URLSearchParams(searchParams);
|
|
||||||
|
|
||||||
params.forEach((value, key) => {
|
|
||||||
switch (key) {
|
|
||||||
case 'select':
|
|
||||||
if (value === 'all') {
|
|
||||||
events.push({ type: 'selectAll' });
|
|
||||||
} else if (value === 'affected') {
|
|
||||||
events.push({ type: 'selectAffected' });
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'focus':
|
|
||||||
events.push({ type: 'focusProject', projectName: value });
|
|
||||||
break;
|
|
||||||
case 'groupByFolder':
|
|
||||||
events.push({ type: 'setGroupByFolder', groupByFolder: true });
|
|
||||||
break;
|
|
||||||
case 'collapseEdges':
|
|
||||||
events.push({ type: 'setCollapseEdges', collapseEdges: true });
|
|
||||||
break;
|
|
||||||
case 'searchDepth':
|
|
||||||
const parsedValue = parseInt(value, 10);
|
|
||||||
|
|
||||||
if (parsedValue === 0) {
|
|
||||||
events.push({
|
|
||||||
type: 'setSearchDepthEnabled',
|
|
||||||
searchDepthEnabled: false,
|
|
||||||
});
|
|
||||||
} else if (parsedValue > 1) {
|
|
||||||
events.push({
|
|
||||||
type: 'setSearchDepth',
|
|
||||||
searchDepth: parseInt(value),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
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',
|
|
||||||
projectName: value,
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
case 'traceEnd':
|
|
||||||
events.push({ type: 'setTracingEnd', projectName: value });
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return events;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const routeListener: InvokeCallback<
|
|
||||||
ProjectGraphMachineEvents,
|
|
||||||
ProjectGraphMachineEvents
|
|
||||||
> = (callback) => {
|
|
||||||
const history = createBrowserHistory();
|
|
||||||
|
|
||||||
parseSearchParamsToEvents(history.location.search).forEach((event) =>
|
|
||||||
callback(event)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@ -1,166 +0,0 @@
|
|||||||
import { assign } from '@xstate/immer';
|
|
||||||
import { createBrowserHistory } from 'history';
|
|
||||||
import { createMachine } from 'xstate';
|
|
||||||
import { RouteEvents } from './interfaces';
|
|
||||||
|
|
||||||
type ParamKeys =
|
|
||||||
| 'focus'
|
|
||||||
| 'groupByFolder'
|
|
||||||
| 'searchDepth'
|
|
||||||
| 'select'
|
|
||||||
| 'collapseEdges'
|
|
||||||
| 'traceStart'
|
|
||||||
| 'traceEnd'
|
|
||||||
| 'traceAlgorithm';
|
|
||||||
type ParamRecord = Record<ParamKeys, string | null>;
|
|
||||||
|
|
||||||
function reduceParamRecordToQueryString(params: ParamRecord): string {
|
|
||||||
const newParams = Object.entries(params).reduce((acc, [key, value]) => {
|
|
||||||
if (value !== null) {
|
|
||||||
acc[key] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return new URLSearchParams(newParams).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RouteSetterContext {
|
|
||||||
currentParamString: string;
|
|
||||||
params: Record<ParamKeys, string | null>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createRouteMachine = () => {
|
|
||||||
const history = createBrowserHistory();
|
|
||||||
|
|
||||||
const params = new URLSearchParams(history.location.search);
|
|
||||||
const paramRecord: ParamRecord = {
|
|
||||||
focus: params.get('focus'),
|
|
||||||
groupByFolder: params.get('groupByFolder'),
|
|
||||||
collapseEdges: params.get('collapseEdges'),
|
|
||||||
searchDepth: params.get('searchDepth'),
|
|
||||||
select: params.get('select'),
|
|
||||||
traceStart: params.get('traceStart'),
|
|
||||||
traceEnd: params.get('traceEnd'),
|
|
||||||
traceAlgorithm: params.get('traceAlgorithm'),
|
|
||||||
};
|
|
||||||
|
|
||||||
const initialContext: RouteSetterContext = {
|
|
||||||
currentParamString: reduceParamRecordToQueryString(paramRecord),
|
|
||||||
params: paramRecord,
|
|
||||||
};
|
|
||||||
|
|
||||||
return createMachine<RouteSetterContext, RouteEvents>(
|
|
||||||
{
|
|
||||||
predictableActionArguments: true,
|
|
||||||
id: 'route',
|
|
||||||
context: {
|
|
||||||
currentParamString: '',
|
|
||||||
params: {
|
|
||||||
focus: null,
|
|
||||||
groupByFolder: null,
|
|
||||||
searchDepth: null,
|
|
||||||
select: null,
|
|
||||||
collapseEdges: null,
|
|
||||||
traceStart: null,
|
|
||||||
traceEnd: null,
|
|
||||||
traceAlgorithm: null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
always: {
|
|
||||||
actions: assign((ctx) => {
|
|
||||||
const history = createBrowserHistory();
|
|
||||||
|
|
||||||
const newParamString = reduceParamRecordToQueryString(ctx.params);
|
|
||||||
|
|
||||||
history.push({
|
|
||||||
hash: history.location.hash,
|
|
||||||
search: newParamString,
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.currentParamString = newParamString;
|
|
||||||
}),
|
|
||||||
cond: 'didParamsChange',
|
|
||||||
},
|
|
||||||
on: {
|
|
||||||
notifyRouteSelectAll: {
|
|
||||||
actions: assign((ctx) => {
|
|
||||||
ctx.params.select = 'all';
|
|
||||||
ctx.params.focus = null;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteSelectAffected: {
|
|
||||||
actions: assign((ctx) => {
|
|
||||||
ctx.params.select = 'affected';
|
|
||||||
ctx.params.focus = null;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteClearSelect: {
|
|
||||||
actions: assign((ctx) => {
|
|
||||||
ctx.params.select = null;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteFocusProject: {
|
|
||||||
actions: assign((ctx, event) => {
|
|
||||||
ctx.params.focus = event.focusedProject;
|
|
||||||
ctx.params.select = null;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteUnfocusProject: {
|
|
||||||
actions: assign((ctx, event) => {
|
|
||||||
ctx.params.focus = null;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteGroupByFolder: {
|
|
||||||
actions: assign((ctx, event) => {
|
|
||||||
ctx.params.groupByFolder = event.groupByFolder ? 'true' : null;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteCollapseEdges: {
|
|
||||||
actions: assign((ctx, event) => {
|
|
||||||
ctx.params.collapseEdges = event.collapseEdges ? 'true' : null;
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteSearchDepth: {
|
|
||||||
actions: assign((ctx, event) => {
|
|
||||||
if (event.searchDepthEnabled === false) {
|
|
||||||
ctx.params.searchDepth = '0';
|
|
||||||
} else if (event.searchDepthEnabled && event.searchDepth !== 1) {
|
|
||||||
ctx.params.searchDepth = event.searchDepth.toString();
|
|
||||||
} else {
|
|
||||||
ctx.params.searchDepth = null;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
notifyRouteTracing: {
|
|
||||||
actions: assign((ctx, event) => {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
guards: {
|
|
||||||
didParamsChange: (ctx) => {
|
|
||||||
const cond =
|
|
||||||
ctx.currentParamString !==
|
|
||||||
reduceParamRecordToQueryString(ctx.params);
|
|
||||||
|
|
||||||
return cond;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
).withContext(initialContext);
|
|
||||||
};
|
|
||||||
@ -6,6 +6,7 @@ import { getEnvironmentConfig } from './hooks/use-environment-config';
|
|||||||
// nx-ignore-next-line
|
// nx-ignore-next-line
|
||||||
import { ProjectGraphClientResponse } from 'nx/src/command-line/dep-graph';
|
import { ProjectGraphClientResponse } from 'nx/src/command-line/dep-graph';
|
||||||
import { getProjectGraphDataService } from './hooks/get-project-graph-data-service';
|
import { getProjectGraphDataService } from './hooks/get-project-graph-data-service';
|
||||||
|
import { getProjectGraphService } from './machines/get-services';
|
||||||
|
|
||||||
const { appConfig } = getEnvironmentConfig();
|
const { appConfig } = getEnvironmentConfig();
|
||||||
const projectGraphDataService = getProjectGraphDataService();
|
const projectGraphDataService = getProjectGraphDataService();
|
||||||
@ -52,7 +53,32 @@ const taskDataLoader = async (selectedWorkspaceId: string) => {
|
|||||||
const childRoutes: RouteObject[] = [
|
const childRoutes: RouteObject[] = [
|
||||||
{
|
{
|
||||||
path: 'projects',
|
path: 'projects',
|
||||||
element: <ProjectsSidebar />,
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <ProjectsSidebar />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'all',
|
||||||
|
element: <ProjectsSidebar />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'affected',
|
||||||
|
element: <ProjectsSidebar />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':focusedProject',
|
||||||
|
element: <ProjectsSidebar />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'trace/:startTrace',
|
||||||
|
element: <ProjectsSidebar />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'trace/:startTrace/:endTrace',
|
||||||
|
element: <ProjectsSidebar />,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
loader: async ({ request, params }) => {
|
loader: async ({ request, params }) => {
|
||||||
|
|||||||
@ -47,7 +47,9 @@ export function DebouncedTextInput({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
updateTextFilter(debouncedValue);
|
if (debouncedValue !== '') {
|
||||||
|
updateTextFilter(debouncedValue);
|
||||||
|
}
|
||||||
}, [debouncedValue, updateTextFilter]);
|
}, [debouncedValue, updateTextFilter]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,19 +0,0 @@
|
|||||||
import { Link, LinkProps, useSearchParams, To } from 'react-router-dom';
|
|
||||||
import React from 'react';
|
|
||||||
|
|
||||||
type LinkWithSearchParamsProps = LinkProps &
|
|
||||||
React.RefAttributes<HTMLAnchorElement>;
|
|
||||||
|
|
||||||
function LinkWithSearchParams(props: LinkWithSearchParamsProps) {
|
|
||||||
const [searchParams] = useSearchParams();
|
|
||||||
|
|
||||||
let to: To;
|
|
||||||
if (typeof props.to === 'object') {
|
|
||||||
to = { ...props.to, search: searchParams.toString() };
|
|
||||||
} else if (typeof props.to === 'string') {
|
|
||||||
to = { pathname: props.to, search: searchParams.toString() };
|
|
||||||
}
|
|
||||||
return <Link {...props} to={to} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default LinkWithSearchParams;
|
|
||||||
@ -1,7 +1,9 @@
|
|||||||
import { getProjectGraphService } from '../machines/get-services';
|
import { getProjectGraphService } from '../machines/get-services';
|
||||||
import { FlagIcon, MapPinIcon } from '@heroicons/react/24/solid';
|
import { FlagIcon, MapPinIcon } from '@heroicons/react/24/solid';
|
||||||
import Tag from '../ui-components/tag';
|
import Tag from '../ui-components/tag';
|
||||||
import { TooltipButton } from './tooltip-button';
|
import { TooltipButton, TooltipLinkButton } from './tooltip-button';
|
||||||
|
import { useRouteConstructor } from '../util';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
export interface ProjectNodeToolTipProps {
|
export interface ProjectNodeToolTipProps {
|
||||||
type: 'app' | 'lib' | 'e2e';
|
type: 'app' | 'lib' | 'e2e';
|
||||||
@ -15,33 +17,25 @@ export function ProjectNodeToolTip({
|
|||||||
tags,
|
tags,
|
||||||
}: ProjectNodeToolTipProps) {
|
}: ProjectNodeToolTipProps) {
|
||||||
const projectGraphService = getProjectGraphService();
|
const projectGraphService = getProjectGraphService();
|
||||||
|
const { start, end, algorithm } =
|
||||||
function onFocus() {
|
projectGraphService.getSnapshot().context.tracing;
|
||||||
projectGraphService.send({
|
const routeConstructor = useRouteConstructor();
|
||||||
type: 'focusProject',
|
const navigate = useNavigate();
|
||||||
projectName: id,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function onExclude() {
|
function onExclude() {
|
||||||
projectGraphService.send({
|
projectGraphService.send({
|
||||||
type: 'deselectProject',
|
type: 'deselectProject',
|
||||||
projectName: id,
|
projectName: id,
|
||||||
});
|
});
|
||||||
|
navigate(routeConstructor('/projects', true));
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStartTrace() {
|
function onStartTrace() {
|
||||||
projectGraphService.send({
|
navigate(routeConstructor(`/projects/trace/${id}`, true));
|
||||||
type: 'setTracingStart',
|
|
||||||
projectName: id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndTrace() {
|
function onEndTrace() {
|
||||||
projectGraphService.send({
|
navigate(routeConstructor(`/projects/trace/${start}/${id}`, true));
|
||||||
type: 'setTracingEnd',
|
|
||||||
projectName: id,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -58,22 +52,27 @@ export function ProjectNodeToolTip({
|
|||||||
</p>
|
</p>
|
||||||
) : null}
|
) : null}
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<TooltipButton onClick={onFocus}>Focus</TooltipButton>
|
<TooltipLinkButton to={routeConstructor(`/projects/${id}`, true)}>
|
||||||
|
Focus
|
||||||
|
</TooltipLinkButton>
|
||||||
<TooltipButton onClick={onExclude}>Exclude</TooltipButton>
|
<TooltipButton onClick={onExclude}>Exclude</TooltipButton>
|
||||||
<TooltipButton
|
{!start ? (
|
||||||
className="flex flex-row items-center"
|
<TooltipButton
|
||||||
onClick={onStartTrace}
|
className="flex flex-row items-center"
|
||||||
>
|
onClick={onStartTrace}
|
||||||
<MapPinIcon className="mr-2 h-5 w-5 text-slate-500"></MapPinIcon>
|
>
|
||||||
Start
|
<MapPinIcon className="mr-2 h-5 w-5 text-slate-500"></MapPinIcon>
|
||||||
</TooltipButton>
|
Start
|
||||||
<TooltipButton
|
</TooltipButton>
|
||||||
className="flex flex-row items-center"
|
) : (
|
||||||
onClick={onEndTrace}
|
<TooltipButton
|
||||||
>
|
className="flex flex-row items-center"
|
||||||
<FlagIcon className="mr-2 h-5 w-5 text-slate-500"></FlagIcon>
|
onClick={onEndTrace}
|
||||||
End
|
>
|
||||||
</TooltipButton>
|
<FlagIcon className="mr-2 h-5 w-5 text-slate-500"></FlagIcon>
|
||||||
|
End
|
||||||
|
</TooltipButton>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
/* eslint-disable-next-line */
|
/* eslint-disable-next-line */
|
||||||
import { Link, LinkProps } from 'react-router-dom';
|
import { Link, LinkProps } from 'react-router-dom';
|
||||||
import { HTMLAttributes } from 'react';
|
import { HTMLAttributes } from 'react';
|
||||||
import LinkWithSearchParams from '../ui-components/link-with-current-search-params';
|
|
||||||
|
|
||||||
const sharedClasses =
|
const sharedClasses =
|
||||||
'inline-flex items-center rounded-md border border-slate-300 bg-slate-50 py-2 px-4 mt-2 mr-2 text-slate-500 hover:bg-slate-100 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700';
|
'inline-flex items-center rounded-md border border-slate-300 bg-slate-50 py-2 px-4 mt-2 mr-2 text-slate-500 hover:bg-slate-100 dark:border-slate-600 dark:bg-slate-800 dark:text-slate-300 hover:dark:bg-slate-700';
|
||||||
@ -25,12 +24,8 @@ export function TooltipLinkButton({
|
|||||||
...rest
|
...rest
|
||||||
}: LinkProps) {
|
}: LinkProps) {
|
||||||
return (
|
return (
|
||||||
<LinkWithSearchParams
|
<Link className={`${sharedClasses} ${className}`} to={to} {...rest}>
|
||||||
className={`${sharedClasses} ${className}`}
|
|
||||||
to={to}
|
|
||||||
{...rest}
|
|
||||||
>
|
|
||||||
{children}
|
{children}
|
||||||
</LinkWithSearchParams>
|
</Link>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,43 @@
|
|||||||
// nx-ignore-next-line
|
// nx-ignore-next-line
|
||||||
import { ProjectGraphDependency, ProjectGraphNode } from '@nrwl/devkit';
|
import { ProjectGraphDependency, ProjectGraphNode } from '@nrwl/devkit';
|
||||||
|
import { getEnvironmentConfig } from './hooks/use-environment-config';
|
||||||
|
import { To, useParams, useSearchParams } from 'react-router-dom';
|
||||||
|
|
||||||
export function trimBackSlash(value: string): string {
|
export const useRouteConstructor = (): ((
|
||||||
return value.replace(/\/$/, '');
|
to: To,
|
||||||
}
|
retainSearchParams: true
|
||||||
|
) => To) => {
|
||||||
|
const { environment } = getEnvironmentConfig();
|
||||||
|
const { selectedWorkspaceId } = useParams();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
|
||||||
|
return (to: To, retainSearchParams: true) => {
|
||||||
|
let pathname = '';
|
||||||
|
|
||||||
|
if (typeof to === 'object') {
|
||||||
|
if (environment === 'dev') {
|
||||||
|
pathname = `/${selectedWorkspaceId}${to.pathname}`;
|
||||||
|
} else {
|
||||||
|
pathname = to.pathname;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...to,
|
||||||
|
pathname,
|
||||||
|
search: retainSearchParams ? searchParams.toString() : '',
|
||||||
|
};
|
||||||
|
} else if (typeof to === 'string') {
|
||||||
|
if (environment === 'dev') {
|
||||||
|
pathname = `/${selectedWorkspaceId}${to}`;
|
||||||
|
} else {
|
||||||
|
pathname = to;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
pathname,
|
||||||
|
search: retainSearchParams ? searchParams.toString() : '',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export function parseParentDirectoriesFromFilePath(
|
export function parseParentDirectoriesFromFilePath(
|
||||||
path: string,
|
path: string,
|
||||||
|
|||||||
@ -1423,83 +1423,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "new-lib",
|
|
||||||
"type": "lib",
|
|
||||||
"data": {
|
|
||||||
"tags": [],
|
|
||||||
"root": "libs/new-lib",
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/.eslintrc.json",
|
|
||||||
"hash": "69f0f5128f733f3ef756c81439f0548eb3f314ff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/jest.config.ts",
|
|
||||||
"hash": "4920380a6eaa2ffaa6ac16eafcccb60622ab0dc0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/project.json",
|
|
||||||
"hash": "12563cc2fb5447cd596a4a46766ac0e089c35e36"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/README.md",
|
|
||||||
"hash": "ae28060a863433273a37b6a6818126817b405add"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/src/index.ts",
|
|
||||||
"hash": "001f7c36454094a6f9a387e47b14445eab276fce"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/src/lib/new-lib.module.ts",
|
|
||||||
"hash": "4936692048161ebc3cfbf0d146327a7b3c9de46e",
|
|
||||||
"deps": ["npm:@angular/core", "npm:@angular/common"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/src/test-setup.ts",
|
|
||||||
"hash": "1100b3e8a6ed08f4b5c27a96471846d57023c320",
|
|
||||||
"deps": ["npm:jest-preset-angular"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/tsconfig.json",
|
|
||||||
"hash": "1c995b83bf3715a370457c4296b1a11f40572cff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/tsconfig.lib.json",
|
|
||||||
"hash": "8e00439a4ac91e9d14eae4b313f59c1d435003ee"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/tsconfig.spec.json",
|
|
||||||
"hash": "c5db02778f96a2a200d787c0a7b376fe0d6c36f7"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"targets": {
|
|
||||||
"test": {
|
|
||||||
"executor": "@nrwl/jest:jest",
|
|
||||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
||||||
"options": {
|
|
||||||
"jestConfig": "libs/new-lib/jest.config.ts",
|
|
||||||
"passWithNoTests": true
|
|
||||||
},
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production",
|
|
||||||
"{workspaceRoot}/jest.preset.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nrwl/linter:eslint",
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": [
|
|
||||||
"libs/new-lib/**/*.ts",
|
|
||||||
"libs/new-lib/**/*.html"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"inputs": ["default", "{workspaceRoot}/.eslintrc.json"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "cart",
|
"name": "cart",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
@ -1539,12 +1462,7 @@
|
|||||||
{
|
{
|
||||||
"file": "apps/cart/src/app/app.tsx",
|
"file": "apps/cart/src/app/app.tsx",
|
||||||
"hash": "e971864bdab1bea4c48550c2ab1d9e0e8489e753",
|
"hash": "e971864bdab1bea4c48550c2ab1d9e0e8489e753",
|
||||||
"deps": [
|
"deps": ["npm:react-router-dom", "shared-header", "cart-cart-page"]
|
||||||
"npm:react-router-dom",
|
|
||||||
"new-lib",
|
|
||||||
"shared-header",
|
|
||||||
"cart-cart-page"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "apps/cart/src/assets/.gitkeep",
|
"file": "apps/cart/src/assets/.gitkeep",
|
||||||
@ -1858,7 +1776,6 @@
|
|||||||
"type": "static"
|
"type": "static"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"new-lib": [],
|
|
||||||
"cart": [
|
"cart": [
|
||||||
{
|
{
|
||||||
"source": "cart",
|
"source": "cart",
|
||||||
@ -1872,7 +1789,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"source": "cart",
|
"source": "cart",
|
||||||
"target": "new-lib",
|
|
||||||
"type": "static"
|
"type": "static"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1423,83 +1423,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "new-lib",
|
|
||||||
"type": "lib",
|
|
||||||
"data": {
|
|
||||||
"tags": [],
|
|
||||||
"root": "libs/new-lib",
|
|
||||||
"files": [
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/.eslintrc.json",
|
|
||||||
"hash": "69f0f5128f733f3ef756c81439f0548eb3f314ff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/jest.config.ts",
|
|
||||||
"hash": "4920380a6eaa2ffaa6ac16eafcccb60622ab0dc0"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/project.json",
|
|
||||||
"hash": "12563cc2fb5447cd596a4a46766ac0e089c35e36"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/README.md",
|
|
||||||
"hash": "ae28060a863433273a37b6a6818126817b405add"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/src/index.ts",
|
|
||||||
"hash": "001f7c36454094a6f9a387e47b14445eab276fce"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/src/lib/new-lib.module.ts",
|
|
||||||
"hash": "4936692048161ebc3cfbf0d146327a7b3c9de46e",
|
|
||||||
"deps": ["npm:@angular/core", "npm:@angular/common"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/src/test-setup.ts",
|
|
||||||
"hash": "1100b3e8a6ed08f4b5c27a96471846d57023c320",
|
|
||||||
"deps": ["npm:jest-preset-angular"]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/tsconfig.json",
|
|
||||||
"hash": "1c995b83bf3715a370457c4296b1a11f40572cff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/tsconfig.lib.json",
|
|
||||||
"hash": "8e00439a4ac91e9d14eae4b313f59c1d435003ee"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"file": "libs/new-lib/tsconfig.spec.json",
|
|
||||||
"hash": "c5db02778f96a2a200d787c0a7b376fe0d6c36f7"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"targets": {
|
|
||||||
"test": {
|
|
||||||
"executor": "@nrwl/jest:jest",
|
|
||||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
|
||||||
"options": {
|
|
||||||
"jestConfig": "libs/new-lib/jest.config.ts",
|
|
||||||
"passWithNoTests": true
|
|
||||||
},
|
|
||||||
"inputs": [
|
|
||||||
"default",
|
|
||||||
"^production",
|
|
||||||
"{workspaceRoot}/jest.preset.js"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"lint": {
|
|
||||||
"executor": "@nrwl/linter:eslint",
|
|
||||||
"options": {
|
|
||||||
"lintFilePatterns": [
|
|
||||||
"libs/new-lib/**/*.ts",
|
|
||||||
"libs/new-lib/**/*.html"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"inputs": ["default", "{workspaceRoot}/.eslintrc.json"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "cart",
|
"name": "cart",
|
||||||
"type": "app",
|
"type": "app",
|
||||||
@ -1539,12 +1462,7 @@
|
|||||||
{
|
{
|
||||||
"file": "apps/cart/src/app/app.tsx",
|
"file": "apps/cart/src/app/app.tsx",
|
||||||
"hash": "e971864bdab1bea4c48550c2ab1d9e0e8489e753",
|
"hash": "e971864bdab1bea4c48550c2ab1d9e0e8489e753",
|
||||||
"deps": [
|
"deps": ["npm:react-router-dom", "shared-header", "cart-cart-page"]
|
||||||
"npm:react-router-dom",
|
|
||||||
"new-lib",
|
|
||||||
"shared-header",
|
|
||||||
"cart-cart-page"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"file": "apps/cart/src/assets/.gitkeep",
|
"file": "apps/cart/src/assets/.gitkeep",
|
||||||
@ -1858,7 +1776,6 @@
|
|||||||
"type": "static"
|
"type": "static"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"new-lib": [],
|
|
||||||
"cart": [
|
"cart": [
|
||||||
{
|
{
|
||||||
"source": "cart",
|
"source": "cart",
|
||||||
@ -1872,7 +1789,6 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"source": "cart",
|
"source": "cart",
|
||||||
"target": "new-lib",
|
|
||||||
"type": "static"
|
"type": "static"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -548,40 +548,6 @@
|
|||||||
"products:deploy": []
|
"products:deploy": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"new-lib:test": {
|
|
||||||
"roots": ["new-lib:test"],
|
|
||||||
"tasks": {
|
|
||||||
"new-lib:test": {
|
|
||||||
"id": "new-lib:test",
|
|
||||||
"target": {
|
|
||||||
"project": "new-lib",
|
|
||||||
"target": "test"
|
|
||||||
},
|
|
||||||
"projectRoot": "libs/new-lib",
|
|
||||||
"overrides": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"new-lib:test": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"new-lib:lint": {
|
|
||||||
"roots": ["new-lib:lint"],
|
|
||||||
"tasks": {
|
|
||||||
"new-lib:lint": {
|
|
||||||
"id": "new-lib:lint",
|
|
||||||
"target": {
|
|
||||||
"project": "new-lib",
|
|
||||||
"target": "lint"
|
|
||||||
},
|
|
||||||
"projectRoot": "libs/new-lib",
|
|
||||||
"overrides": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"new-lib:lint": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cart:build": {
|
"cart:build": {
|
||||||
"roots": ["cart:build:production"],
|
"roots": ["cart:build:production"],
|
||||||
"tasks": {
|
"tasks": {
|
||||||
|
|||||||
@ -548,40 +548,6 @@
|
|||||||
"products:deploy": []
|
"products:deploy": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"new-lib:test": {
|
|
||||||
"roots": ["new-lib:test"],
|
|
||||||
"tasks": {
|
|
||||||
"new-lib:test": {
|
|
||||||
"id": "new-lib:test",
|
|
||||||
"target": {
|
|
||||||
"project": "new-lib",
|
|
||||||
"target": "test"
|
|
||||||
},
|
|
||||||
"projectRoot": "libs/new-lib",
|
|
||||||
"overrides": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"new-lib:test": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"new-lib:lint": {
|
|
||||||
"roots": ["new-lib:lint"],
|
|
||||||
"tasks": {
|
|
||||||
"new-lib:lint": {
|
|
||||||
"id": "new-lib:lint",
|
|
||||||
"target": {
|
|
||||||
"project": "new-lib",
|
|
||||||
"target": "lint"
|
|
||||||
},
|
|
||||||
"projectRoot": "libs/new-lib",
|
|
||||||
"overrides": {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"new-lib:lint": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"cart:build": {
|
"cart:build": {
|
||||||
"roots": ["cart:build:production"],
|
"roots": ["cart:build:production"],
|
||||||
"tasks": {
|
"tasks": {
|
||||||
|
|||||||
@ -178,26 +178,40 @@ export class GraphService {
|
|||||||
renderTime: 0,
|
renderTime: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.renderGraph && elementsToSendToRender) {
|
if (this.renderGraph) {
|
||||||
this.renderGraph.setElements(elementsToSendToRender);
|
if (elementsToSendToRender) {
|
||||||
|
this.renderGraph.setElements(elementsToSendToRender);
|
||||||
|
|
||||||
if (event.type === 'notifyGraphFocusProject') {
|
if (event.type === 'notifyGraphFocusProject') {
|
||||||
this.renderGraph.setFocussedElement(event.projectName);
|
this.renderGraph.setFocussedElement(event.projectName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { numEdges, numNodes } = this.renderGraph.render();
|
||||||
|
|
||||||
|
selectedProjectNames = (
|
||||||
|
elementsToSendToRender.nodes('[type!="dir"]') ?? []
|
||||||
|
).map((node) => node.id());
|
||||||
|
|
||||||
|
const renderTime = Date.now() - time;
|
||||||
|
|
||||||
|
perfReport = {
|
||||||
|
renderTime,
|
||||||
|
numNodes,
|
||||||
|
numEdges,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const { numEdges, numNodes } = this.renderGraph.render();
|
||||||
|
|
||||||
|
this.renderGraph.getCurrentlyShownProjectIds();
|
||||||
|
|
||||||
|
const renderTime = Date.now() - time;
|
||||||
|
|
||||||
|
perfReport = {
|
||||||
|
renderTime,
|
||||||
|
numNodes,
|
||||||
|
numEdges,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const { numEdges, numNodes } = this.renderGraph.render();
|
|
||||||
|
|
||||||
selectedProjectNames = (
|
|
||||||
elementsToSendToRender.nodes('[type!="dir"]') ?? []
|
|
||||||
).map((node) => node.id());
|
|
||||||
|
|
||||||
const renderTime = Date.now() - time;
|
|
||||||
|
|
||||||
perfReport = {
|
|
||||||
renderTime,
|
|
||||||
numNodes,
|
|
||||||
numEdges,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.lastPerformanceReport = perfReport;
|
this.lastPerformanceReport = perfReport;
|
||||||
|
|||||||
@ -76,41 +76,6 @@ export type ProjectGraphRenderEvents =
|
|||||||
algorithm: TracingAlgorithmType;
|
algorithm: TracingAlgorithmType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type RouteEvents =
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteFocusProject';
|
|
||||||
focusedProject: string;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteGroupByFolder';
|
|
||||||
groupByFolder: boolean;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteCollapseEdges';
|
|
||||||
collapseEdges: boolean;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteSearchDepth';
|
|
||||||
searchDepthEnabled: boolean;
|
|
||||||
searchDepth: number;
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteUnfocusProject';
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteSelectAll';
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteSelectAffected';
|
|
||||||
}
|
|
||||||
| { type: 'notifyRouteClearSelect' }
|
|
||||||
| {
|
|
||||||
type: 'notifyRouteTracing';
|
|
||||||
start: string;
|
|
||||||
end: string;
|
|
||||||
algorithm: TracingAlgorithmType;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TaskGraphRecord = Record<string, TaskGraph>;
|
export type TaskGraphRecord = Record<string, TaskGraph>;
|
||||||
export type TaskGraphRenderEvents =
|
export type TaskGraphRenderEvents =
|
||||||
| {
|
| {
|
||||||
|
|||||||
@ -397,18 +397,18 @@ async function startServer(
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (openBrowser) {
|
if (openBrowser) {
|
||||||
let url = `http://${host}:${port}`;
|
let url = `http://${host}:${port}/projects`;
|
||||||
let params = new URLSearchParams();
|
let params = new URLSearchParams();
|
||||||
|
|
||||||
if (focus) {
|
if (focus) {
|
||||||
params.append('focus', focus);
|
url += `/${focus}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupByFolder) {
|
if (groupByFolder) {
|
||||||
params.append('groupByFolder', 'true');
|
params.append('groupByFolder', 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
open(`${url}/projects?${params.toString()}`);
|
open(`${url}?${params.toString()}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user