Skip to content

Commit

Permalink
feat(docs): add {% project-details %} as a tag in markdown docs (nrwl…
Browse files Browse the repository at this point in the history
…#21288)

Co-authored-by: Colum Ferry <[email protected]>
Co-authored-by: Isaac Mann <[email protected]>
  • Loading branch information
3 people authored Jan 24, 2024
1 parent 292d407 commit 7b680ec
Show file tree
Hide file tree
Showing 36 changed files with 1,473 additions and 649 deletions.
43 changes: 43 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,49 @@ Have a more decent button-like widget that you can place below sections of a tut
{% video-link link="https://youtu.be/OQ-Zc5tcxJE?t=64" /%}
```

#### Project Details View

Embed a Project Details View that is identical what is shown in Nx Console or `nx show project myproject --web`

````markdown
{% project-details title="Test" height="100px" %}

```json
{
"project": {
"name": "demo",
"data": {
"root": " packages/demo",
"projectType": "application",
"targets": {
"dev": {
"executor": "nx:run-commands",
"options": {
"command": "vite dev"
}
},
"build": {
"executor": "nx:run-commands",
"inputs": ["production", "^production"],
"outputs": ["{projectRoot}/dist"],
"options": {
"command": "vite build"
}
}
}
}
},
"sourceMap": {
"targets": ["packages/demo/vite.config.ts", "@nx/vite"],
"targets.dev": ["packages/demo/vite.config.ts", "@nx/vite"],
"targets.build": ["packages/demo/vite.config.ts", "@nx/vite"]
}
}
```

{% /project-details %}
````

#### Graph

Embed an Nx Graph visualization that can be panned by the user.
Expand Down
3 changes: 1 addition & 2 deletions graph/client/src/app/routes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ import { Shell } from './shell';
/* eslint-disable @nx/enforce-module-boundaries */
// nx-ignore-next-line
import { ProjectGraphClientResponse } from 'nx/src/command-line/graph/graph';
/* eslint-enable @nx/enforce-module-boundaries */
import { ProjectDetailsPage } from '@nx/graph/project-details';
import {
getEnvironmentConfig,
getProjectGraphDataService,
} from '@nx/graph/shared';
import { TasksSidebarErrorBoundary } from './feature-tasks/tasks-sidebar-error-boundary';
import { ProjectDetailsPage } from '@nx/graph/project-details';

const { appConfig } = getEnvironmentConfig();
const projectGraphDataService = getProjectGraphDataService();
Expand Down
5 changes: 3 additions & 2 deletions graph/client/src/app/ui-components/project-details-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// nx-ignore-next-line
import { useFloating } from '@floating-ui/react';
import { XMarkIcon } from '@heroicons/react/24/outline';
import { ProjectDetails } from '@nx/graph/project-details';
import { ProjectDetailsWrapper } from '@nx/graph/project-details';
/* eslint-disable @nx/enforce-module-boundaries */
// nx-ignore-next-line
import { ProjectGraphClientResponse } from 'nx/src/command-line/graph/graph';
Expand Down Expand Up @@ -46,6 +46,7 @@ export function ProjectDetailsModal() {
setSearchParams(searchParams);
setIsOpen(false);
}

return (
isOpen && (
<div
Expand All @@ -56,7 +57,7 @@ export function ProjectDetailsModal() {
ref={refs.setFloating}
>
<div className="rounded-md h-full border border-slate-500">
<ProjectDetails project={project} sourceMap={sourceMap} />
<ProjectDetailsWrapper project={project} sourceMap={sourceMap} />
<div className="top-2 right-2 absolute" onClick={onClose}>
<XMarkIcon className="h-4 w-4" />
</div>
Expand Down
2 changes: 1 addition & 1 deletion graph/project-details/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export * from './lib/project-details';
export * from './lib/project-details-wrapper';
export * from './lib/project-details-page';
10 changes: 4 additions & 6 deletions graph/project-details/src/lib/project-details-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import { ProjectGraphProjectNode } from '@nx/devkit';
import {
Link,
ScrollRestoration,
useLocation,
useNavigate,
useParams,
useRouteLoaderData,
} from 'react-router-dom';
import ProjectDetails from './project-details';
import { ProjectDetailsWrapper } from './project-details-wrapper';
import {
fetchProjectGraph,
getProjectGraphDataService,
Expand Down Expand Up @@ -54,7 +52,7 @@ export function ProjectDetailsPage() {
<div className="flex flex-col justify-center w-full text-slate-700 dark:text-slate-400">
<ScrollRestoration />
{environment !== 'nx-console' ? (
<header className="flex w-full justify-center items-center px-4 py-2 border-b-2 border-slate-900/10 mb-16 dark:border-slate-300/10">
<header className="flex w-full justify-center items-center px-4 py-2 border-b-2 border-slate-900/10 mb-8 dark:border-slate-300/10">
<div className="flex flex-grow items-center justify-between max-w-6xl">
<svg
className="h-10 w-auto text-slate-900 dark:text-white"
Expand Down Expand Up @@ -85,10 +83,10 @@ export function ProjectDetailsPage() {
</header>
) : null}
<div className="flex-grow mx-auto w-full max-w-6xl px-8 mb-8">
<ProjectDetails
<ProjectDetailsWrapper
project={project}
sourceMap={sourceMap}
></ProjectDetails>
></ProjectDetailsWrapper>
</div>
</div>
);
Expand Down
163 changes: 163 additions & 0 deletions graph/project-details/src/lib/project-details-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars

import { useNavigate, useSearchParams } from 'react-router-dom';

/* eslint-disable @nx/enforce-module-boundaries */
// nx-ignore-next-line
import { ProjectGraphProjectNode } from '@nx/devkit';
import {
getExternalApiService,
useEnvironmentConfig,
useRouteConstructor,
} from '@nx/graph/shared';
import {
ProjectDetails,
ProjectDetailsImperativeHandle,
} from '@nx/graph/ui-project-details';
import { useCallback, useLayoutEffect, useRef } from 'react';

export interface ProjectDetailsProps {
project: ProjectGraphProjectNode;
sourceMap: Record<string, string[]>;
}

export function ProjectDetailsWrapper(props: ProjectDetailsProps) {
const projectDetailsRef = useRef<ProjectDetailsImperativeHandle>(null);
const environment = useEnvironmentConfig()?.environment;
const externalApiService = getExternalApiService();
const navigate = useNavigate();
const routeConstructor = useRouteConstructor();
const [searchParams, setSearchParams] = useSearchParams();

const handleViewInProjectGraph = useCallback(
(data: { projectName: string }) => {
if (environment === 'nx-console') {
externalApiService.postEvent({
type: 'open-project-graph',
payload: {
projectName: data.projectName,
},
});
} else {
navigate(
routeConstructor(
`/projects/${encodeURIComponent(data.projectName)}`,
true
)
);
}
},
[externalApiService, routeConstructor, navigate, environment]
);

const handleViewInTaskGraph = useCallback(
(data: { projectName: string; targetName: string }) => {
if (environment === 'nx-console') {
externalApiService.postEvent({
type: 'open-task-graph',
payload: {
projectName: data.projectName,
targetName: data.targetName,
},
});
} else {
navigate(
routeConstructor(
{
pathname: `/tasks/${encodeURIComponent(data.targetName)}`,
search: `?projects=${encodeURIComponent(data.projectName)}`,
},
true
)
);
}
},
[externalApiService, routeConstructor, navigate, environment]
);

const handleRunTarget = useCallback(
(data: { projectName: string; targetName: string }) => {
externalApiService.postEvent({
type: 'run-task',
payload: { taskId: `${data.projectName}:${data.targetName}` },
});
},
[externalApiService]
);

const updateSearchParams = (params: URLSearchParams, sections: string[]) => {
if (sections.length === 0) {
params.delete('expanded');
} else {
params.set('expanded', sections.join(','));
}
};

const handleTargetCollapse = useCallback(
(targetName: string) => {
setSearchParams(
(currentSearchParams) => {
const expandedSections =
currentSearchParams.get('expanded')?.split(',') || [];
const newExpandedSections = expandedSections.filter(
(section) => section !== targetName
);
updateSearchParams(currentSearchParams, newExpandedSections);
return currentSearchParams;
},
{
replace: true,
preventScrollReset: true,
}
);
},
[setSearchParams]
);

const handleTargetExpand = useCallback(
(targetName: string) => {
setSearchParams(
(currentSearchParams) => {
const expandedSections =
currentSearchParams.get('expanded')?.split(',') || [];
if (!expandedSections.includes(targetName)) {
expandedSections.push(targetName);
updateSearchParams(currentSearchParams, expandedSections);
}
return currentSearchParams;
},
{ replace: true, preventScrollReset: true }
);
},
[setSearchParams]
);

// On initial render, expand the sections that are included in the URL search params.
const isExpandedHandled = useRef(false);
useLayoutEffect(() => {
if (!props.project.data.targets) return;
if (isExpandedHandled.current) return;
isExpandedHandled.current = true;

const expandedSections = searchParams.get('expanded')?.split(',') || [];
for (const targetName of Object.keys(props.project.data.targets)) {
if (expandedSections.includes(targetName)) {
projectDetailsRef.current?.expandTarget(targetName);
}
}
}, [searchParams, props.project.data.targets, projectDetailsRef]);

return (
<ProjectDetails
ref={projectDetailsRef}
{...props}
onTargetCollapse={handleTargetCollapse}
onTargetExpand={handleTargetExpand}
onViewInProjectGraph={handleViewInProjectGraph}
onViewInTaskGraph={handleViewInTaskGraph}
onRunTarget={environment === 'nx-console' ? handleRunTarget : undefined}
/>
);
}

export default ProjectDetailsWrapper;
Loading

0 comments on commit 7b680ec

Please sign in to comment.