diff --git a/graph/client/src/app/feature-projects/machines/composite-graph.state.ts b/graph/client/src/app/feature-projects/machines/composite-graph.state.ts
index 3f7dcbc4891be..d34d6806ce83d 100644
--- a/graph/client/src/app/feature-projects/machines/composite-graph.state.ts
+++ b/graph/client/src/app/feature-projects/machines/composite-graph.state.ts
@@ -34,6 +34,43 @@ export const compositeGraphStateConfig: ProjectGraphStateNodeConfig = {
}),
],
on: {
+ selectAll: {
+ actions: [
+ assign((ctx, event) => {
+ if (event.type !== 'selectAll') return;
+ ctx.compositeGraph.enabled = true;
+ ctx.compositeGraph.context = null;
+ }),
+ send((ctx) => ({
+ type: 'enableCompositeGraph',
+ context: ctx.compositeGraph.context,
+ })),
+ ],
+ },
+ deselectAll: {
+ actions: [
+ assign((ctx, event) => {
+ if (event.type !== 'deselectAll') return;
+ ctx.compositeGraph.enabled = true;
+ }),
+ send(
+ () => ({
+ type: 'notifyGraphHideAllProjects',
+ }),
+ { to: (context) => context.graphActor }
+ ),
+ ],
+ },
+ selectAffected: {
+ actions: [
+ send(
+ () => ({
+ type: 'notifyGraphShowAffectedProjects',
+ }),
+ { to: (context) => context.graphActor }
+ ),
+ ],
+ },
focusProject: {
actions: [
assign((ctx, event) => {
@@ -112,6 +149,7 @@ export const compositeGraphStateConfig: ProjectGraphStateNodeConfig = {
if (event.type !== 'enableCompositeGraph') return;
ctx.compositeGraph.enabled = true;
ctx.compositeGraph.context = event.context || undefined;
+ ctx.focusedProject = null;
}),
send(
(ctx, event) => ({
diff --git a/graph/client/src/app/feature-projects/panels/group-by-folder-panel.tsx b/graph/client/src/app/feature-projects/panels/group-by-folder-panel.tsx
index 34e5ef3fc964d..f17c5ff5fd7c4 100644
--- a/graph/client/src/app/feature-projects/panels/group-by-folder-panel.tsx
+++ b/graph/client/src/app/feature-projects/panels/group-by-folder-panel.tsx
@@ -3,11 +3,15 @@ import { CheckboxPanel } from '../../ui-components/checkbox-panel';
export interface DisplayOptionsPanelProps {
groupByFolder: boolean;
groupByFolderChanged: (checked: boolean) => void;
+ disabled?: boolean;
+ disabledDescription?: string;
}
export const GroupByFolderPanel = ({
groupByFolder,
groupByFolderChanged,
+ disabled,
+ disabledDescription,
}: DisplayOptionsPanelProps) => {
return (
);
};
diff --git a/graph/client/src/app/feature-projects/project-list.tsx b/graph/client/src/app/feature-projects/project-list.tsx
index 33af5316eb9c8..ef9a906934575 100644
--- a/graph/client/src/app/feature-projects/project-list.tsx
+++ b/graph/client/src/app/feature-projects/project-list.tsx
@@ -283,13 +283,8 @@ function CompositeNodeListItem({
No composite nodes;
}
diff --git a/graph/client/src/app/feature-projects/projects-sidebar.tsx b/graph/client/src/app/feature-projects/projects-sidebar.tsx
index 676f318bdb084..52c05eb1b6a1d 100644
--- a/graph/client/src/app/feature-projects/projects-sidebar.tsx
+++ b/graph/client/src/app/feature-projects/projects-sidebar.tsx
@@ -7,6 +7,8 @@ import { useProjectGraphSelector } from './hooks/use-project-graph-selector';
import { TracingAlgorithmType } from './machines/interfaces';
import {
collapseEdgesSelector,
+ compositeContextSelector,
+ compositeGraphEnabledSelector,
focusedProjectNameSelector,
getTracingInfo,
groupByFolderSelector,
@@ -40,6 +42,8 @@ import {
} from 'react-router-dom';
import { useCurrentPath } from '../hooks/use-current-path';
import { ProjectDetailsModal } from '../ui-components/project-details-modal';
+import { CompositeGraphPanel } from './panels/composite-graph-panel';
+import { CompositeContextPanel } from '../ui-components/composite-context-panel';
export function ProjectsSidebar(): JSX.Element {
const environmentConfig = useEnvironmentConfig();
@@ -53,6 +57,10 @@ export function ProjectsSidebar(): JSX.Element {
);
const groupByFolder = useProjectGraphSelector(groupByFolderSelector);
const collapseEdges = useProjectGraphSelector(collapseEdgesSelector);
+ const compositeEnabled = useProjectGraphSelector(
+ compositeGraphEnabledSelector
+ );
+ const compositeContext = useProjectGraphSelector(compositeContextSelector);
const isTracing = projectGraphService.getSnapshot().matches('tracing');
const tracingInfo = useProjectGraphSelector(getTracingInfo);
@@ -75,17 +83,48 @@ export function ProjectsSidebar(): JSX.Element {
navigate(routeConstructor('/projects', true));
}
+ function resetCompositeContext() {
+ projectGraphService.send({ type: 'enableCompositeGraph', context: null });
+ navigate(
+ routeConstructor(
+ { pathname: '/projects', search: '?composite=true' },
+ true
+ )
+ );
+ }
+
function showAllProjects() {
- navigate(routeConstructor('/projects/all', true));
+ navigate(
+ routeConstructor('/projects/all', (searchParams) => {
+ if (searchParams.has('composite')) {
+ searchParams.set('composite', 'true');
+ }
+ return searchParams;
+ })
+ );
}
function hideAllProjects() {
projectGraphService.send({ type: 'deselectAll' });
- navigate(routeConstructor('/projects', true));
+ navigate(
+ routeConstructor('/projects', (searchParams) => {
+ if (searchParams.has('composite')) {
+ searchParams.set('composite', 'true');
+ }
+ return searchParams;
+ })
+ );
}
function showAffectedProjects() {
- navigate(routeConstructor('/projects/affected', true));
+ navigate(
+ routeConstructor('/projects/affected', (searchParams) => {
+ if (searchParams.has('composite')) {
+ searchParams.set('composite', 'true');
+ }
+ return searchParams;
+ })
+ );
}
function searchDepthFilterEnabledChange(checked: boolean) {
@@ -126,6 +165,17 @@ export function ProjectsSidebar(): JSX.Element {
});
}
+ function compositeEnabledChanged(checked: boolean) {
+ setSearchParams((currentSearchParams) => {
+ if (checked) {
+ currentSearchParams.set('composite', 'true');
+ } else {
+ currentSearchParams.delete('composite');
+ }
+ return currentSearchParams;
+ });
+ }
+
function incrementDepthFilter() {
const newSearchDepth = searchDepthInfo.searchDepth + 1;
setSearchParams((currentSearchParams) => {
@@ -224,7 +274,7 @@ export function ProjectsSidebar(): JSX.Element {
projectName: routeParams.endTrace,
});
}
- }, [routeParams]);
+ }, [routeParams, compositeEnabled]);
useEffect(() => {
if (searchParams.has('groupByFolder') && groupByFolder === false) {
@@ -251,6 +301,17 @@ export function ProjectsSidebar(): JSX.Element {
});
}
+ if (searchParams.has('composite')) {
+ const compositeParam = searchParams.get('composite');
+ projectGraphService.send({
+ type: 'enableCompositeGraph',
+ context: compositeParam === 'true' ? null : compositeParam,
+ });
+ } else if (!searchParams.has('composite')) {
+ projectGraphService.send({ type: 'disableCompositeGraph' });
+ navigate(routeConstructor('/projects', true));
+ }
+
if (searchParams.has('searchDepth')) {
const parsedValue = parseInt(searchParams.get('searchDepth'), 10);
@@ -329,6 +390,13 @@ export function ProjectsSidebar(): JSX.Element {
<>
+ {compositeEnabled && compositeContext ? (
+
+ ) : null}
+
{focusedProject ? (
-
+
Experimental Features
@@ -386,6 +456,10 @@ export function ProjectsSidebar(): JSX.Element {
collapseEdges={collapseEdges}
collapseEdgesChanged={collapseEdgesChanged}
>
+
diff --git a/graph/client/src/app/ui-components/checkbox-panel.tsx b/graph/client/src/app/ui-components/checkbox-panel.tsx
index 9fea965cac1d8..90ac08e1ae3ff 100644
--- a/graph/client/src/app/ui-components/checkbox-panel.tsx
+++ b/graph/client/src/app/ui-components/checkbox-panel.tsx
@@ -1,4 +1,5 @@
import { memo } from 'react';
+import classNames from 'classnames';
export interface CheckboxPanelProps {
checked: boolean;
@@ -6,12 +7,28 @@ export interface CheckboxPanelProps {
name: string;
label: string;
description: string;
+ disabled?: boolean;
+ disabledDescription?: string;
}
export const CheckboxPanel = memo(
- ({ checked, checkChanged, label, description, name }: CheckboxPanelProps) => {
+ ({
+ checked,
+ checkChanged,
+ label,
+ description,
+ name,
+ disabled,
+ disabledDescription,
+ }: CheckboxPanelProps) => {
return (
-
+
checkChanged(event.target.checked)}
checked={checked}
+ disabled={disabled}
/>
diff --git a/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx b/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx
index 9bcf1c0f2e5d5..7ac1caa3c9dd8 100644
--- a/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx
+++ b/graph/client/src/app/ui-tooltips/graph-tooltip-display.tsx
@@ -41,17 +41,16 @@ export function TooltipDisplay() {
});
break;
case 'focus-node': {
- const to =
- action.tooltipNodeType === 'compositeNode'
- ? routeConstructor(
- {
- pathname: `/projects`,
- search: `?composite=true&compositeContext=${action.id}`,
- },
- false
- )
- : routeConstructor(`/projects/${action.id}`, true);
- navigate(to);
+ if (action.tooltipNodeType === 'compositeNode') {
+ navigate(
+ routeConstructor(
+ { pathname: `/projects`, search: `?composite=${action.id}` },
+ true
+ )
+ );
+ } else {
+ navigate(routeConstructor(`/projects/${action.id}`, true));
+ }
break;
}
case 'collapse-node':
diff --git a/package.json b/package.json
index a2105a7786e12..c84bcfd5078cf 100644
--- a/package.json
+++ b/package.json
@@ -319,7 +319,7 @@
"@markdoc/markdoc": "0.2.2",
"@monaco-editor/react": "^4.4.6",
"@napi-rs/canvas": "^0.1.52",
- "@nx/graph": "0.0.1-alpha.15",
+ "@nx/graph": "0.0.1-alpha.17",
"@react-spring/three": "^9.7.3",
"@react-three/drei": "^9.108.3",
"@react-three/fiber": "^8.16.8",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index cb638601f93ab..aa6a54d78d231 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -31,8 +31,8 @@ importers:
specifier: ^0.1.52
version: 0.1.52
'@nx/graph':
- specifier: 0.0.1-alpha.15
- version: 0.0.1-alpha.15(@nx/devkit@19.7.0-beta.6(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))))(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react-router-dom@6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
+ specifier: 0.0.1-alpha.17
+ version: 0.0.1-alpha.17(@nx/devkit@19.7.0-beta.6(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))))(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react-router-dom@6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)
'@react-spring/three':
specifier: ^9.7.3
version: 9.7.3(@react-three/fiber@8.16.8(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(three@0.166.1))(react@18.3.1)(three@0.166.1)
@@ -5776,8 +5776,8 @@ packages:
'@zkochan/js-yaml':
optional: true
- '@nx/graph@0.0.1-alpha.15':
- resolution: {integrity: sha512-wwotjQcUCz46NknyvZ99Pi0qpvVul6Maa1Y+bvcd6SUgrpmbfW/zyMQejlyq+iKufZCTJv/iiDUIKZEKvvVRjw==}
+ '@nx/graph@0.0.1-alpha.17':
+ resolution: {integrity: sha512-s1pe+om4dk0vGojjv1yHQIRNbeIajHs66glS/lcZP2YovCLWXy+3OBmM1jzzWrKIW1fdSwamO5S9WBdWnAPKFQ==}
peerDependencies:
'@nx/devkit': '>= 19 < 20'
nx: '>= 19 < 20'
@@ -25471,7 +25471,7 @@ snapshots:
- supports-color
- verdaccio
- '@nx/graph@0.0.1-alpha.15(@nx/devkit@19.7.0-beta.6(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))))(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react-router-dom@6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
+ '@nx/graph@0.0.1-alpha.17(@nx/devkit@19.7.0-beta.6(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11))))(nx@19.7.0-beta.6(@swc-node/register@1.9.1(@swc/core@1.5.7(@swc/helpers@0.5.11))(@swc/types@0.1.7)(typescript@5.5.3))(@swc/core@1.5.7(@swc/helpers@0.5.11)))(react-dom@18.3.1(react@18.3.1))(react-router-dom@6.23.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1))(react@18.3.1)':
dependencies:
'@floating-ui/react': 0.26.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
'@headlessui/react': 1.7.19(react-dom@18.3.1(react@18.3.1))(react@18.3.1)