diff --git a/graph/client/src/app/feature-projects/projects-sidebar.tsx b/graph/client/src/app/feature-projects/projects-sidebar.tsx index ba9e665315..336305cdf2 100644 --- a/graph/client/src/app/feature-projects/projects-sidebar.tsx +++ b/graph/client/src/app/feature-projects/projects-sidebar.tsx @@ -1,5 +1,4 @@ import { useCallback, useEffect, useState } from 'react'; -import { useIntervalWhen } from '../hooks/use-interval-when'; import { getProjectGraphService } from '../machines/get-services'; import { ExperimentalFeature } from '../ui-components/experimental-feature'; import { FocusedPanel } from '../ui-components/focused-panel'; @@ -27,14 +26,19 @@ import { ProjectList } from './project-list'; import { ProjectGraphClientResponse } from 'nx/src/command-line/graph/graph'; /* eslint-enable @nx/enforce-module-boundaries */ import { useFloating } from '@floating-ui/react'; -import { useEnvironmentConfig, useRouteConstructor } from '@nx/graph/shared'; +import { + fetchProjectGraph, + getProjectGraphDataService, + useEnvironmentConfig, + useIntervalWhen, + useRouteConstructor, +} from '@nx/graph/shared'; import { useNavigate, useParams, useRouteLoaderData, useSearchParams, } from 'react-router-dom'; -import { getProjectGraphDataService } from '../hooks/get-project-graph-data-service'; import { useCurrentPath } from '../hooks/use-current-path'; import { ProjectDetailsModal } from '../ui-components/project-details-modal'; @@ -293,28 +297,18 @@ export function ProjectsSidebar(): JSX.Element { useIntervalWhen( () => { - const selectedWorkspaceId = - params.selectedWorkspaceId ?? - environmentConfig.appConfig.defaultWorkspaceId; - - const projectInfo = environmentConfig.appConfig.workspaces.find( - (graph) => graph.id === selectedWorkspaceId - ); - - const fetchProjectGraph = async () => { - const response: ProjectGraphClientResponse = - await projectGraphDataService.getProjectGraph( - projectInfo.projectGraphUrl - ); + fetchProjectGraph( + projectGraphDataService, + params, + environmentConfig.appConfig + ).then((response: ProjectGraphClientResponse) => { projectGraphService.send({ type: 'updateGraph', projects: response.projects, dependencies: response.dependencies, fileMap: response.fileMap, }); - }; - - fetchProjectGraph(); + }); }, 5000, environmentConfig.watch diff --git a/graph/client/src/app/hooks/get-project-graph-data-service.ts b/graph/client/src/app/hooks/get-project-graph-data-service.ts deleted file mode 100644 index 67b5167714..0000000000 --- a/graph/client/src/app/hooks/get-project-graph-data-service.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { FetchProjectGraphService } from '../fetch-project-graph-service'; -import { ProjectGraphService } from '../interfaces'; -import { LocalProjectGraphService } from '../local-project-graph-service'; -import { MockProjectGraphService } from '../mock-project-graph-service'; -import { NxConsoleProjectGraphService } from '../nx-console-project-graph-service'; - -let projectGraphService: ProjectGraphService; - -export function getProjectGraphDataService() { - if (projectGraphService === undefined) { - if (window.environment === 'dev') { - projectGraphService = new FetchProjectGraphService(); - } else if (window.environment === 'watch') { - projectGraphService = new MockProjectGraphService(); - } else if (window.environment === 'nx-console') { - projectGraphService = new NxConsoleProjectGraphService(); - } else if (window.environment === 'release') { - if (window.localMode === 'build') { - projectGraphService = new LocalProjectGraphService(); - } else { - projectGraphService = new FetchProjectGraphService(); - } - } - } - - return projectGraphService; -} diff --git a/graph/client/src/app/machines/graph.service.ts b/graph/client/src/app/machines/graph.service.ts index 667cda207d..94267370f2 100644 --- a/graph/client/src/app/machines/graph.service.ts +++ b/graph/client/src/app/machines/graph.service.ts @@ -1,6 +1,8 @@ import { GraphService } from '@nx/graph/ui-graph'; -import { getProjectGraphDataService } from '../hooks/get-project-graph-data-service'; -import { getEnvironmentConfig } from '@nx/graph/shared'; +import { + getEnvironmentConfig, + getProjectGraphDataService, +} from '@nx/graph/shared'; import { selectValueByThemeStatic } from '@nx/graph/ui-theme'; let graphService: GraphService; diff --git a/graph/client/src/app/routes.tsx b/graph/client/src/app/routes.tsx index 2e492e929c..0dbb4ec218 100644 --- a/graph/client/src/app/routes.tsx +++ b/graph/client/src/app/routes.tsx @@ -7,9 +7,11 @@ import { Shell } from './shell'; import { ProjectGraphClientResponse } from 'nx/src/command-line/graph/graph'; /* eslint-enable @nx/enforce-module-boundaries */ import { ProjectDetailsPage } from '@nx/graph/project-details'; -import { getEnvironmentConfig } from '@nx/graph/shared'; +import { + getEnvironmentConfig, + getProjectGraphDataService, +} from '@nx/graph/shared'; import { TasksSidebarErrorBoundary } from './feature-tasks/tasks-sidebar-error-boundary'; -import { getProjectGraphDataService } from './hooks/get-project-graph-data-service'; const { appConfig } = getEnvironmentConfig(); const projectGraphDataService = getProjectGraphDataService(); @@ -78,6 +80,7 @@ const projectDetailsLoader = async ( (project) => project.name === projectName ); return { + hash: workspaceData.hash, project, sourceMap: sourceMaps[project.data.root], }; diff --git a/graph/project-details/src/lib/project-details-page.tsx b/graph/project-details/src/lib/project-details-page.tsx index 900d58d43e..78ee2fde2d 100644 --- a/graph/project-details/src/lib/project-details-page.tsx +++ b/graph/project-details/src/lib/project-details-page.tsx @@ -1,25 +1,58 @@ /* eslint-disable @nx/enforce-module-boundaries */ // nx-ignore-next-line import { ProjectGraphProjectNode } from '@nx/devkit'; -import { Link, useRouteLoaderData } from 'react-router-dom'; +import { + Link, + ScrollRestoration, + useLocation, + useNavigate, + useParams, + useRouteLoaderData, +} from 'react-router-dom'; import ProjectDetails from './project-details'; -import { useEnvironmentConfig, useRouteConstructor } from '@nx/graph/shared'; +import { + fetchProjectGraph, + getProjectGraphDataService, + useEnvironmentConfig, + useIntervalWhen, + useRouteConstructor, +} from '@nx/graph/shared'; import { ThemePanel } from '@nx/graph/ui-theme'; export function ProjectDetailsPage() { - const { project, sourceMap } = useRouteLoaderData( + const { project, sourceMap, hash } = useRouteLoaderData( 'selectedProjectDetails' ) as { + hash: string; project: ProjectGraphProjectNode; sourceMap: Record; }; - const environment = useEnvironmentConfig()?.environment; + const { environment, watch, appConfig } = useEnvironmentConfig(); + + const projectGraphDataService = getProjectGraphDataService(); + const params = useParams(); + + useIntervalWhen( + async () => { + fetchProjectGraph(projectGraphDataService, params, appConfig).then( + (data) => { + if (data?.hash !== hash) { + window.location.reload(); + } + return; + } + ); + }, + 1000, + watch + ); const routeConstructor = useRouteConstructor(); return (
+ {environment !== 'nx-console' ? (
diff --git a/graph/shared/src/index.ts b/graph/shared/src/index.ts index 93220b4e20..dd2268fea7 100644 --- a/graph/shared/src/index.ts +++ b/graph/shared/src/index.ts @@ -3,3 +3,6 @@ export * from './lib/external-api-service'; export * from './lib/use-environment-config'; export * from './lib/app-config'; export * from './lib/use-route-constructor'; +export * from './lib/use-interval-when'; +export * from './lib/project-graph-data-service/get-project-graph-data-service'; +export * from './lib/fetch-project-graph'; diff --git a/graph/shared/src/lib/fetch-project-graph.ts b/graph/shared/src/lib/fetch-project-graph.ts new file mode 100644 index 0000000000..b9bf15787c --- /dev/null +++ b/graph/shared/src/lib/fetch-project-graph.ts @@ -0,0 +1,18 @@ +import { Params } from 'react-router-dom'; +import { ProjectGraphService } from './project-graph-data-service/get-project-graph-data-service'; +import { AppConfig } from './app-config'; + +export async function fetchProjectGraph( + projectGraphService: ProjectGraphService, + params: Readonly>, + appConfig: AppConfig +) { + const selectedWorkspaceId = + params.selectedWorkspaceId ?? appConfig.defaultWorkspaceId; + + const projectInfo = appConfig.workspaces.find( + (graph) => graph.id === selectedWorkspaceId + ); + + return await projectGraphService.getProjectGraph(projectInfo.projectGraphUrl); +} diff --git a/graph/client/src/app/fetch-project-graph-service.ts b/graph/shared/src/lib/project-graph-data-service/fetch-project-graph-service.ts similarity index 95% rename from graph/client/src/app/fetch-project-graph-service.ts rename to graph/shared/src/lib/project-graph-data-service/fetch-project-graph-service.ts index 17f82d0298..955af67b32 100644 --- a/graph/client/src/app/fetch-project-graph-service.ts +++ b/graph/shared/src/lib/project-graph-data-service/fetch-project-graph-service.ts @@ -4,8 +4,8 @@ import type { ProjectGraphClientResponse, TaskGraphClientResponse, } from 'nx/src/command-line/graph/graph'; +import { ProjectGraphService } from './get-project-graph-data-service'; /* eslint-enable @nx/enforce-module-boundaries */ -import { ProjectGraphService } from './interfaces'; export class FetchProjectGraphService implements ProjectGraphService { private taskInputsUrl: string; diff --git a/graph/shared/src/lib/project-graph-data-service/get-project-graph-data-service.ts b/graph/shared/src/lib/project-graph-data-service/get-project-graph-data-service.ts new file mode 100644 index 0000000000..707f6223a8 --- /dev/null +++ b/graph/shared/src/lib/project-graph-data-service/get-project-graph-data-service.ts @@ -0,0 +1,44 @@ +import { FetchProjectGraphService } from './fetch-project-graph-service'; +import { LocalProjectGraphService } from './local-project-graph-service'; +import { MockProjectGraphService } from './mock-project-graph-service'; +import { NxConsoleProjectGraphService } from './nx-console-project-graph-service'; + +/* eslint-disable @nx/enforce-module-boundaries */ +// nx-ignore-next-line +import type { + ProjectGraphClientResponse, + TaskGraphClientResponse, +} from 'nx/src/command-line/graph/graph'; + +let projectGraphService: ProjectGraphService; + +export interface ProjectGraphService { + getHash: () => Promise; + getProjectGraph: (url: string) => Promise; + getTaskGraph: (url: string) => Promise; + setTaskInputsUrl?: (url: string) => void; + getExpandedTaskInputs?: (taskId: string) => Promise>; + getSourceMaps?: ( + url: string + ) => Promise>>; +} + +export function getProjectGraphDataService() { + if (projectGraphService === undefined) { + if (window.environment === 'dev') { + projectGraphService = new FetchProjectGraphService(); + } else if (window.environment === 'watch') { + projectGraphService = new MockProjectGraphService(); + } else if (window.environment === 'nx-console') { + projectGraphService = new NxConsoleProjectGraphService(); + } else if (window.environment === 'release') { + if (window.localMode === 'build') { + projectGraphService = new LocalProjectGraphService(); + } else { + projectGraphService = new FetchProjectGraphService(); + } + } + } + + return projectGraphService; +} diff --git a/graph/client/src/app/local-project-graph-service.ts b/graph/shared/src/lib/project-graph-data-service/local-project-graph-service.ts similarity index 93% rename from graph/client/src/app/local-project-graph-service.ts rename to graph/shared/src/lib/project-graph-data-service/local-project-graph-service.ts index 01c4b255c0..716fe09542 100644 --- a/graph/client/src/app/local-project-graph-service.ts +++ b/graph/shared/src/lib/project-graph-data-service/local-project-graph-service.ts @@ -4,8 +4,8 @@ import type { ProjectGraphClientResponse, TaskGraphClientResponse, } from 'nx/src/command-line/graph/graph'; +import { ProjectGraphService } from './get-project-graph-data-service'; /* eslint-enable @nx/enforce-module-boundaries */ -import { ProjectGraphService } from './interfaces'; export class LocalProjectGraphService implements ProjectGraphService { async getHash(): Promise { diff --git a/graph/client/src/app/mock-project-graph-service.ts b/graph/shared/src/lib/project-graph-data-service/mock-project-graph-service.ts similarity index 93% rename from graph/client/src/app/mock-project-graph-service.ts rename to graph/shared/src/lib/project-graph-data-service/mock-project-graph-service.ts index 3fb9efc7ef..ca18670f74 100644 --- a/graph/client/src/app/mock-project-graph-service.ts +++ b/graph/shared/src/lib/project-graph-data-service/mock-project-graph-service.ts @@ -9,8 +9,8 @@ import type { ProjectGraphClientResponse, TaskGraphClientResponse, } from 'nx/src/command-line/graph/graph'; +import { ProjectGraphService } from './get-project-graph-data-service'; /* eslint-enable @nx/enforce-module-boundaries */ -import { ProjectGraphService } from '../app/interfaces'; export class MockProjectGraphService implements ProjectGraphService { private projectGraphsResponse: ProjectGraphClientResponse = { @@ -84,6 +84,12 @@ export class MockProjectGraphService implements ProjectGraphService { return new Promise((resolve) => resolve(this.taskGraphsResponse)); } + getSourceMaps( + url: string + ): Promise>> { + return new Promise((resolve) => resolve({})); + } + private createNewProject(): ProjectGraphProjectNode { const type = Math.random() > 0.25 ? 'lib' : 'app'; const name = `${type}-${this.projectGraphsResponse.projects.length + 1}`; diff --git a/graph/client/src/app/nx-console-project-graph-service.ts b/graph/shared/src/lib/project-graph-data-service/nx-console-project-graph-service.ts similarity index 93% rename from graph/client/src/app/nx-console-project-graph-service.ts rename to graph/shared/src/lib/project-graph-data-service/nx-console-project-graph-service.ts index d359240257..7148bb119e 100644 --- a/graph/client/src/app/nx-console-project-graph-service.ts +++ b/graph/shared/src/lib/project-graph-data-service/nx-console-project-graph-service.ts @@ -4,7 +4,7 @@ import type { ProjectGraphClientResponse, TaskGraphClientResponse, } from 'nx/src/command-line/graph/graph'; -import { ProjectGraphService } from './interfaces'; +import { ProjectGraphService } from './get-project-graph-data-service'; export class NxConsoleProjectGraphService implements ProjectGraphService { async getHash(): Promise { diff --git a/graph/client/src/app/hooks/use-interval-when.ts b/graph/shared/src/lib/use-interval-when.ts similarity index 100% rename from graph/client/src/app/hooks/use-interval-when.ts rename to graph/shared/src/lib/use-interval-when.ts diff --git a/packages/nx/src/command-line/show/show.ts b/packages/nx/src/command-line/show/show.ts index ba4b4d7014..f3c29ef75c 100644 --- a/packages/nx/src/command-line/show/show.ts +++ b/packages/nx/src/command-line/show/show.ts @@ -100,7 +100,7 @@ export async function showProjectHandler( { view: 'project-details', focus: node.name, - watch: false, + watch: true, open: true, }, []