feat(graph): add description and tags to details page (#26252)

<!-- Please make sure you have read the submission guidelines before
posting an PR -->
<!--
https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr
-->

<!-- Please make sure that your commit message follows our format -->
<!-- Example: `fix(nx): must begin with lowercase` -->

## Current Behavior
<!-- This is the behavior we have today -->

## Expected Behavior
<!-- This is the behavior we should expect with the changes in this PR
-->
<img width="1155" alt="Screenshot 2024-05-29 at 5 47 20 PM"
src="https://github.com/nrwl/nx/assets/16211801/025f08d5-52cf-4087-94a5-e3319c89f8b1">
<img width="1127" alt="Screenshot 2024-05-29 at 5 47 04 PM"
src="https://github.com/nrwl/nx/assets/16211801/ff19514d-2513-4b13-ac9c-4b124ac0ce4a">
<img width="387" alt="Screenshot 2024-06-04 at 11 56 54 PM"
src="https://github.com/nrwl/nx/assets/16211801/ea2f0c47-a444-4be8-9ccd-60fd2b534e12">



## Related Issue(s)
<!-- Please link the issue being fixed so it gets closed when this is
merged. -->

Fixes #
This commit is contained in:
Emily Xiong 2024-06-14 14:27:14 -04:00 committed by GitHub
parent b61546fc1a
commit e9b7439ce2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 101 additions and 47 deletions

View File

@ -103,13 +103,10 @@ export function sourcesRenderer(
} }
} }
return ( return (
<span <span className="group/line flex" key={`code-group${idx}`}>
className="group/line shrink-1 flex flex min-w-0"
key={`code-group${idx}`}
>
<span>{element}</span> <span>{element}</span>
{sourceElement && ( {sourceElement && (
<span className="shrink-1 inline flex min-w-0 pl-2 opacity-0 transition-opacity duration-150 ease-in-out group-hover/line:opacity-100"> <span className="min-w-0 flex-1 pl-2 opacity-0 transition-opacity duration-150 ease-in-out group-hover/line:opacity-100">
{sourceElement} {sourceElement}
</span> </span>
)} )}

View File

@ -34,18 +34,6 @@ const typeToProjectType = {
e2e: 'E2E', e2e: 'E2E',
}; };
function getDisplayType(project: ProjectGraphProjectNode) {
if (project.data.projectType) {
return (
project.data.projectType &&
project.data.projectType?.charAt(0)?.toUpperCase() +
project.data.projectType?.slice(1)
);
} else {
return typeToProjectType[project.type] ?? 'Library';
}
}
export const ProjectDetails = ({ export const ProjectDetails = ({
project, project,
sourceMap, sourceMap,
@ -58,8 +46,6 @@ export const ProjectDetails = ({
const projectData = project.data; const projectData = project.data;
const isCompact = variant === 'compact'; const isCompact = variant === 'compact';
const displayType = getDisplayType(project);
const technologies = [ const technologies = [
...new Set( ...new Set(
[ [
@ -112,24 +98,33 @@ export const ProjectDetails = ({
</div> </div>
<div className="flex justify-between py-2"> <div className="flex justify-between py-2">
<div> <div>
{projectData.metadata?.description ? (
<p className="mb-2 text-sm capitalize text-gray-500 dark:text-slate-400">
{projectData.metadata?.description}
</p>
) : null}
{projectData.tags && projectData.tags.length ? ( {projectData.tags && projectData.tags.length ? (
<p> <p>
<span className="inline-block w-10 font-medium">Tags:</span> <span className="font-medium">Tags:</span>
{projectData.tags?.map((tag) => ( {projectData.tags?.map((tag) => (
<span className="ml-2 font-mono"> <span className="ml-2 font-mono lowercase">
<Pill text={tag} /> <Pill text={tag} />
</span> </span>
))} ))}
</p> </p>
) : null} ) : null}
<p> {projectData.root ? (
<span className="inline-block w-10 font-medium">Root:</span>
<span className="font-mono"> {projectData.root}</span>
</p>
{displayType ? (
<p> <p>
<span className="inline-block w-10 font-medium">Type:</span> <span className="font-medium">Root:</span>
<span className="font-mono"> {displayType}</span> <span className="font-mono"> {projectData.root.trim()}</span>
</p>
) : null}
{projectData.projectType ?? typeToProjectType[project.type] ? (
<p>
<span className="font-medium">Type:</span>
<span className="ml-2 font-mono capitalize">
{projectData.projectType ?? typeToProjectType[project.type]}
</span>
</p> </p>
) : null} ) : null}
</div> </div>

View File

@ -31,6 +31,9 @@ export function TargetConfigurationGroupList({
return ( return (
<> <>
{Object.entries(targetsGroup.groups).map(([targetGroupName, targets]) => { {Object.entries(targetsGroup.groups).map(([targetGroupName, targets]) => {
if (targets.length === 0) {
return null;
}
return ( return (
<TargetConfigurationGroupContainer <TargetConfigurationGroupContainer
targetGroupName={targetGroupName} targetGroupName={targetGroupName}

View File

@ -50,7 +50,7 @@ export function ProjectNodeToolTip({
)} )}
</h4> </h4>
{tags.length > 0 ? ( {tags.length > 0 ? (
<p className="my-2"> <p className="my-2 lowercase">
<strong>tags</strong> <strong>tags</strong>
<br></br> <br></br>
{tags.join(', ')} {tags.join(', ')}

View File

@ -138,7 +138,7 @@ export function Tooltip({
width: 'max-content', width: 'max-content',
...animationStyles, ...animationStyles,
}} }}
className="z-10 min-w-[250px] rounded-md border border-slate-500" className="z-10 min-w-[250px] max-w-prose rounded-md border border-slate-500"
{...getFloatingProps()} {...getFloatingProps()}
> >
{showTooltipArrow && ( {showTooltipArrow && (

View File

@ -26,9 +26,11 @@ describe('Workspaces', () => {
await fs.createFiles({ await fs.createFiles({
'packages/my-package/package.json': JSON.stringify({ 'packages/my-package/package.json': JSON.stringify({
name: 'my-package', name: 'my-package',
description: 'my-package description',
}), }),
'package.json': JSON.stringify({ 'package.json': JSON.stringify({
name: 'package-name', name: 'package-name',
description: 'package description',
workspaces: ['packages/**'], workspaces: ['packages/**'],
}), }),
}); });
@ -54,13 +56,15 @@ describe('Workspaces', () => {
expect(projects['packages/my-package']).toMatchInlineSnapshot(` expect(projects['packages/my-package']).toMatchInlineSnapshot(`
{ {
"metadata": { "metadata": {
"targetGroups": { "description": "my-package description",
"NPM Scripts": [], "targetGroups": {},
},
}, },
"name": "my-package", "name": "my-package",
"root": "packages/my-package", "root": "packages/my-package",
"sourceRoot": "packages/my-package", "sourceRoot": "packages/my-package",
"tags": [
"npm:public",
],
"targets": { "targets": {
"nx-release-publish": { "nx-release-publish": {
"configurations": {}, "configurations": {},

View File

@ -119,6 +119,7 @@ export interface ProjectConfiguration {
} }
export interface ProjectMetadata { export interface ProjectMetadata {
description?: string;
technologies?: string[]; technologies?: string[];
targetGroups?: Record<string, string[]>; targetGroups?: Record<string, string[]>;
} }

View File

@ -23,10 +23,12 @@ describe('nx package.json workspaces plugin', () => {
}), }),
'packages/lib-a/package.json': JSON.stringify({ 'packages/lib-a/package.json': JSON.stringify({
name: 'lib-a', name: 'lib-a',
description: 'lib-a description',
scripts: { test: 'jest' }, scripts: { test: 'jest' },
}), }),
'packages/lib-b/package.json': JSON.stringify({ 'packages/lib-b/package.json': JSON.stringify({
name: 'lib-b', name: 'lib-b',
description: 'lib-b description',
scripts: { scripts: {
build: 'tsc', build: 'tsc',
test: 'jest', test: 'jest',
@ -52,6 +54,7 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
".": { ".": {
"metadata": { "metadata": {
"description": undefined,
"targetGroups": { "targetGroups": {
"NPM Scripts": [ "NPM Scripts": [
"echo", "echo",
@ -61,6 +64,9 @@ describe('nx package.json workspaces plugin', () => {
"name": "root", "name": "root",
"root": ".", "root": ".",
"sourceRoot": ".", "sourceRoot": ".",
"tags": [
"npm:public",
],
"targets": { "targets": {
"echo": { "echo": {
"executor": "nx:run-script", "executor": "nx:run-script",
@ -90,6 +96,7 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
"packages/lib-a": { "packages/lib-a": {
"metadata": { "metadata": {
"description": "lib-a description",
"targetGroups": { "targetGroups": {
"NPM Scripts": [ "NPM Scripts": [
"test", "test",
@ -99,6 +106,9 @@ describe('nx package.json workspaces plugin', () => {
"name": "lib-a", "name": "lib-a",
"root": "packages/lib-a", "root": "packages/lib-a",
"sourceRoot": "packages/lib-a", "sourceRoot": "packages/lib-a",
"tags": [
"npm:public",
],
"targets": { "targets": {
"nx-release-publish": { "nx-release-publish": {
"dependsOn": [ "dependsOn": [
@ -135,6 +145,7 @@ describe('nx package.json workspaces plugin', () => {
"test", "test",
], ],
"metadata": { "metadata": {
"description": "lib-b description",
"targetGroups": { "targetGroups": {
"NPM Scripts": [ "NPM Scripts": [
"build", "build",
@ -145,6 +156,9 @@ describe('nx package.json workspaces plugin', () => {
"name": "lib-b", "name": "lib-b",
"root": "packages/lib-b", "root": "packages/lib-b",
"sourceRoot": "packages/lib-b", "sourceRoot": "packages/lib-b",
"tags": [
"npm:public",
],
"targets": { "targets": {
"build": { "build": {
"executor": "nx:run-script", "executor": "nx:run-script",
@ -227,13 +241,15 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
"packages/vite": { "packages/vite": {
"metadata": { "metadata": {
"targetGroups": { "description": undefined,
"NPM Scripts": [], "targetGroups": {},
},
}, },
"name": "vite", "name": "vite",
"root": "packages/vite", "root": "packages/vite",
"sourceRoot": "packages/vite", "sourceRoot": "packages/vite",
"tags": [
"npm:public",
],
"targets": { "targets": {
"nx-release-publish": { "nx-release-publish": {
"dependsOn": [ "dependsOn": [
@ -313,13 +329,15 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
"packages/vite": { "packages/vite": {
"metadata": { "metadata": {
"targetGroups": { "description": undefined,
"NPM Scripts": [], "targetGroups": {},
},
}, },
"name": "vite", "name": "vite",
"root": "packages/vite", "root": "packages/vite",
"sourceRoot": "packages/vite", "sourceRoot": "packages/vite",
"tags": [
"npm:public",
],
"targets": { "targets": {
"nx-release-publish": { "nx-release-publish": {
"dependsOn": [ "dependsOn": [
@ -395,13 +413,15 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
"packages/vite": { "packages/vite": {
"metadata": { "metadata": {
"targetGroups": { "description": undefined,
"NPM Scripts": [], "targetGroups": {},
},
}, },
"name": "vite", "name": "vite",
"root": "packages/vite", "root": "packages/vite",
"sourceRoot": "packages/vite", "sourceRoot": "packages/vite",
"tags": [
"npm:public",
],
"targets": { "targets": {
"nx-release-publish": { "nx-release-publish": {
"dependsOn": [ "dependsOn": [
@ -465,6 +485,7 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
"packages/a": { "packages/a": {
"metadata": { "metadata": {
"description": undefined,
"targetGroups": { "targetGroups": {
"NPM Scripts": [ "NPM Scripts": [
"build", "build",
@ -474,6 +495,9 @@ describe('nx package.json workspaces plugin', () => {
"name": "root", "name": "root",
"root": "packages/a", "root": "packages/a",
"sourceRoot": "packages/a", "sourceRoot": "packages/a",
"tags": [
"npm:public",
],
"targets": { "targets": {
"build": { "build": {
"executor": "nx:run-script", "executor": "nx:run-script",
@ -529,6 +553,7 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
"packages/a": { "packages/a": {
"metadata": { "metadata": {
"description": undefined,
"targetGroups": { "targetGroups": {
"NPM Scripts": [ "NPM Scripts": [
"build", "build",
@ -538,6 +563,9 @@ describe('nx package.json workspaces plugin', () => {
"name": "root", "name": "root",
"root": "packages/a", "root": "packages/a",
"sourceRoot": "packages/a", "sourceRoot": "packages/a",
"tags": [
"npm:public",
],
"targets": { "targets": {
"build": { "build": {
"executor": "nx:run-script", "executor": "nx:run-script",
@ -593,13 +621,15 @@ describe('nx package.json workspaces plugin', () => {
"projects": { "projects": {
"packages/a": { "packages/a": {
"metadata": { "metadata": {
"targetGroups": { "description": undefined,
"NPM Scripts": [], "targetGroups": {},
},
}, },
"name": "root", "name": "root",
"root": "packages/a", "root": "packages/a",
"sourceRoot": "packages/a", "sourceRoot": "packages/a",
"tags": [
"npm:public",
],
"targets": { "targets": {
"nx-release-publish": { "nx-release-publish": {
"dependsOn": [ "dependsOn": [

View File

@ -12,6 +12,7 @@ import { output } from '../../utils/output';
import { import {
getMetadataFromPackageJson, getMetadataFromPackageJson,
PackageJson, PackageJson,
getTagsFromPackageJson,
readTargetsFromPackageJson, readTargetsFromPackageJson,
} from '../../utils/package-json'; } from '../../utils/package-json';
import { joinPathFragments } from '../../utils/path'; import { joinPathFragments } from '../../utils/path';
@ -119,6 +120,7 @@ export function buildProjectConfigurationFromPackageJson(
name, name,
...packageJson.nx, ...packageJson.nx,
targets: readTargetsFromPackageJson(packageJson), targets: readTargetsFromPackageJson(packageJson),
tags: getTagsFromPackageJson(packageJson),
metadata: getMetadataFromPackageJson(packageJson), metadata: getMetadataFromPackageJson(packageJson),
}; };

View File

@ -23,6 +23,7 @@ describe('nx project.json plugin', () => {
{ {
'packages/lib-a/project.json': JSON.stringify({ 'packages/lib-a/project.json': JSON.stringify({
name: 'lib-a', name: 'lib-a',
description: 'lib-a project description',
targets: { targets: {
build: { build: {
executor: 'nx:run-commands', executor: 'nx:run-commands',
@ -32,6 +33,7 @@ describe('nx project.json plugin', () => {
}), }),
'packages/lib-a/package.json': JSON.stringify({ 'packages/lib-a/package.json': JSON.stringify({
name: 'lib-a', name: 'lib-a',
description: 'lib-a package description',
scripts: { scripts: {
test: 'jest', test: 'jest',
}, },
@ -47,6 +49,7 @@ describe('nx project.json plugin', () => {
"projects": { "projects": {
"lib-a": { "lib-a": {
"metadata": { "metadata": {
"description": "lib-a package description",
"targetGroups": { "targetGroups": {
"NPM Scripts": [ "NPM Scripts": [
"test", "test",
@ -55,6 +58,9 @@ describe('nx project.json plugin', () => {
}, },
"name": "lib-a", "name": "lib-a",
"root": "packages/lib-a", "root": "packages/lib-a",
"tags": [
"npm:public",
],
"targets": { "targets": {
"nx-release-publish": { "nx-release-publish": {
"dependsOn": [ "dependsOn": [

View File

@ -6,6 +6,7 @@ import { ProjectConfiguration } from '../../../config/workspace-json-project-jso
import { import {
PackageJson, PackageJson,
getMetadataFromPackageJson, getMetadataFromPackageJson,
getTagsFromPackageJson,
readTargetsFromPackageJson, readTargetsFromPackageJson,
} from '../../../utils/package-json'; } from '../../../utils/package-json';
@ -56,6 +57,7 @@ function createProjectFromPackageJsonNextToProjectJson(
root, root,
targets: readTargetsFromPackageJson(packageJson), targets: readTargetsFromPackageJson(packageJson),
metadata: getMetadataFromPackageJson(packageJson), metadata: getMetadataFromPackageJson(packageJson),
tags: getTagsFromPackageJson(packageJson),
} as ProjectConfiguration; } as ProjectConfiguration;
} catch (e) { } catch (e) {
console.log(e); console.log(e);

View File

@ -78,6 +78,8 @@ export interface PackageJson {
'nx-migrations'?: string | NxMigrationsConfiguration; 'nx-migrations'?: string | NxMigrationsConfiguration;
'ng-update'?: string | NxMigrationsConfiguration; 'ng-update'?: string | NxMigrationsConfiguration;
packageManager?: string; packageManager?: string;
description?: string;
keywords?: string[];
} }
export function normalizePackageGroup( export function normalizePackageGroup(
@ -144,15 +146,27 @@ let packageManagerCommand: PackageManagerCommands | undefined;
export function getMetadataFromPackageJson( export function getMetadataFromPackageJson(
packageJson: PackageJson packageJson: PackageJson
): ProjectMetadata { ): ProjectMetadata {
const { scripts, nx } = packageJson ?? {}; const { scripts, nx, description } = packageJson ?? {};
const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {}); const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {});
return { return {
targetGroups: { targetGroups: {
'NPM Scripts': includedScripts, ...(includedScripts.length ? { 'NPM Scripts': includedScripts } : {}),
}, },
description,
}; };
} }
export function getTagsFromPackageJson(packageJson: PackageJson): string[] {
const tags = packageJson.private ? ['npm:private'] : ['npm:public'];
if (packageJson.keywords?.length) {
tags.push(...packageJson.keywords.map((k) => `npm:${k}`));
}
if (packageJson?.nx?.tags?.length) {
tags.push(...packageJson?.nx.tags);
}
return tags;
}
export function readTargetsFromPackageJson(packageJson: PackageJson) { export function readTargetsFromPackageJson(packageJson: PackageJson) {
const { scripts, nx, private: isPrivate } = packageJson ?? {}; const { scripts, nx, private: isPrivate } = packageJson ?? {};
const res: Record<string, TargetConfiguration> = {}; const res: Record<string, TargetConfiguration> = {};