diff --git a/graph/client/src/styles.css b/graph/client/src/styles.css
index e05ff27327..0349580f6f 100644
--- a/graph/client/src/styles.css
+++ b/graph/client/src/styles.css
@@ -1,3 +1,7 @@
+/*! purgecss start ignore */
+@import './syntax-highlight.css';
+/*! purgecss end ignore */
+
@tailwind components;
@tailwind base;
@tailwind utilities;
@@ -6,3 +10,37 @@
.dark {
color-scheme: dark;
}
+
+/**
+ * Tooltips
+ */
+[data-tooltip] {
+ position: relative;
+}
+
+[data-tooltip]:before {
+ background-color: hsla(214, 61%, 11%, 1);
+ border-radius: 0.375rem;
+ color: hsla(0, 0%, 95%, 1);
+ content: attr(data-tooltip);
+ left: 0;
+ opacity: 0;
+ padding: 0.25rem 0.5rem;
+ position: absolute;
+ text-align: center;
+ text-transform: capitalize;
+ top: 120%;
+ transition: opacity 150ms ease-out;
+ visibility: hidden;
+ z-index: 1;
+ width: max-content;
+}
+[data-tooltip][data-tooltip-align-right]:before {
+ left: auto;
+ right: 0;
+}
+
+[data-tooltip]:hover:before {
+ opacity: 1;
+ visibility: visible;
+}
diff --git a/graph/client/src/syntax-highlight.css b/graph/client/src/syntax-highlight.css
new file mode 100644
index 0000000000..a69e9c62b2
--- /dev/null
+++ b/graph/client/src/syntax-highlight.css
@@ -0,0 +1,79 @@
+html {
+ --interactive-muted: #94a3b8;
+}
+.dark {
+ --interactive-muted: #64748b;
+}
+
+.hljs .hljs-comment,
+.hljs .hljs-quote {
+ color: var(--interactive-muted);
+}
+
+.hljs .hljs-addition,
+.hljs .hljs-keyword,
+.hljs .hljs-selector-tag {
+ color: #859900;
+}
+
+.hljs .hljs-doctag,
+.hljs .hljs-literal,
+.hljs .hljs-meta .hljs .hljs-meta-string,
+.hljs .hljs-number,
+.hljs .hljs-regexp,
+.hljs .hljs-string {
+ color: #2aa198;
+}
+
+.hljs .hljs-name,
+.hljs .hljs-section,
+.hljs .hljs-selector-class,
+.hljs .hljs-selector-id,
+.hljs .hljs-title {
+ color: #268bd2;
+}
+
+.hljs .hljs-attr,
+.hljs .hljs-attribute,
+.hljs .hljs-class .hljs .hljs-title,
+.hljs .hljs-template-variable,
+.hljs .hljs-type,
+.hljs .hljs-variable {
+ color: #b58900;
+}
+
+.hljs .hljs-bullet,
+.hljs .hljs-link,
+.hljs .hljs-meta,
+.hljs .hljs-meta .hljs .hljs-keyword,
+.hljs .hljs-selector-attr,
+.hljs .hljs-selector-pseudo,
+.hljs .hljs-subst,
+.hljs .hljs-symbol {
+ color: #cb4b16;
+}
+
+.hljs .hljs-built_in,
+.hljs .hljs-deletion {
+ color: #dc322f;
+}
+
+.hljs .hljs-formula {
+ background: #073642;
+}
+
+.hljs .hljs-emphasis {
+ font-style: italic;
+}
+
+.hljs .hljs-strong {
+ font-weight: 700;
+}
+
+.linenumber {
+ border-color: rgb(59 130 246);
+ background: #e5e7eb;
+}
+html.dark .linenumber {
+ background: #e5e7eb33;
+}
diff --git a/graph/project-details/src/lib/project-details-page.tsx b/graph/project-details/src/lib/project-details-page.tsx
index 2c429ab826..3d90800b91 100644
--- a/graph/project-details/src/lib/project-details-page.tsx
+++ b/graph/project-details/src/lib/project-details-page.tsx
@@ -52,36 +52,25 @@ export function ProjectDetailsPage() {
{environment !== 'nx-console' ? (
-
-
-
-
+
- ) : null}
+ ) : (
+
+ )}
+
{element}
{sourceElement && (
-
+
{sourceElement}
)}
diff --git a/graph/ui-project-details/src/lib/pill.tsx b/graph/ui-project-details/src/lib/pill.tsx
new file mode 100644
index 0000000000..febfb96f15
--- /dev/null
+++ b/graph/ui-project-details/src/lib/pill.tsx
@@ -0,0 +1,28 @@
+import { twMerge } from 'tailwind-merge';
+
+export function Pill({
+ text,
+ color = 'grey',
+ tooltip,
+}: {
+ text: string;
+ color?: 'grey' | 'green' | 'yellow';
+ tooltip?: string;
+}) {
+ return (
+
+ {text}
+
+ );
+}
diff --git a/graph/ui-project-details/src/lib/project-details/project-details.tsx b/graph/ui-project-details/src/lib/project-details/project-details.tsx
index 297409121d..27b0c4d75e 100644
--- a/graph/ui-project-details/src/lib/project-details/project-details.tsx
+++ b/graph/ui-project-details/src/lib/project-details/project-details.tsx
@@ -20,6 +20,7 @@ import {
useRef,
} from 'react';
import { twMerge } from 'tailwind-merge';
+import { Pill } from '../pill';
export interface ProjectDetailsProps {
project: ProjectGraphProjectNode;
@@ -90,34 +91,42 @@ export const ProjectDetails = forwardRef(
>
- {name}{' '}
- {onViewInProjectGraph ? (
- onViewInProjectGraph({ projectName: name })}
- >
- ) : null}{' '}
+ {name}
+
+ {onViewInProjectGraph ? (
+
+ ) : null}{' '}
+
-
- {projectData.tags ? (
+
+ {projectData.tags && projectData.tags.length ? (
+ Tags:
{projectData.tags?.map((tag) => (
-
- {tag}
+
+
))}
) : null}
- Root: {root}
+ Root:
+ {root}
{displayType ? (
- Type: {displayType}
+ Type:
+ {displayType}
) : null}
@@ -128,13 +137,13 @@ export const ProjectDetails = forwardRef(
openAction="hover"
content={(
) as any}
>
-
+
Targets
- {projectTargets.map((targetName) => {
+ {projectTargets.sort(sortNxReleasePublishLast).map((targetName) => {
const target = projectData.targets?.[targetName];
return target && targetRefs.current[targetName] ? (
-
@@ -160,4 +169,10 @@ export const ProjectDetails = forwardRef(
}
);
+function sortNxReleasePublishLast(a: string, b: string) {
+ if (a === 'nx-release-publish') return 1;
+ if (b === 'nx-release-publish') return -1;
+ return 1;
+}
+
export default ProjectDetails;
diff --git a/graph/ui-project-details/src/lib/target-configuration-details/copy-to-clipboard.tsx b/graph/ui-project-details/src/lib/target-configuration-details/copy-to-clipboard.tsx
index c4ce71d3f4..e7cbfdd7ff 100644
--- a/graph/ui-project-details/src/lib/target-configuration-details/copy-to-clipboard.tsx
+++ b/graph/ui-project-details/src/lib/target-configuration-details/copy-to-clipboard.tsx
@@ -3,6 +3,7 @@ import { JSX, useEffect, useState } from 'react';
interface CopyToClipboardProps {
onCopy: () => void;
+ tooltipAlignment?: 'left' | 'right';
}
export function CopyToClipboard(props: CopyToClipboardProps): JSX.Element {
@@ -16,16 +17,20 @@ export function CopyToClipboard(props: CopyToClipboardProps): JSX.Element {
}
});
return (
- {
- e.stopPropagation();
- setCopied(true);
- props.onCopy();
- }}
- >
+
+ {
+ e.stopPropagation();
+ setCopied(true);
+ props.onCopy();
+ }}
+ >
+
);
}
diff --git a/graph/ui-project-details/src/lib/target-configuration-details/fading-collapsible.tsx b/graph/ui-project-details/src/lib/target-configuration-details/fading-collapsible.tsx
index 47d8915de6..deca5ece8a 100644
--- a/graph/ui-project-details/src/lib/target-configuration-details/fading-collapsible.tsx
+++ b/graph/ui-project-details/src/lib/target-configuration-details/fading-collapsible.tsx
@@ -33,7 +33,9 @@ export function FadingCollapsible({ children }: { children: ReactNode }) {
>
diff --git a/graph/ui-project-details/src/lib/target-configuration-details/source-info.tsx b/graph/ui-project-details/src/lib/target-configuration-details/source-info.tsx
index f6e983085f..e51a420ae8 100644
--- a/graph/ui-project-details/src/lib/target-configuration-details/source-info.tsx
+++ b/graph/ui-project-details/src/lib/target-configuration-details/source-info.tsx
@@ -1,15 +1,17 @@
import { SourcemapInfoToolTip, Tooltip } from '@nx/graph/ui-tooltips';
import { InformationCircleIcon } from '@heroicons/react/24/outline';
+import { twMerge } from 'tailwind-merge';
export function SourceInfo(props: {
data: Array
;
propertyKey: string;
+ color?: string;
}) {
// Target property key is in the form `target.${targetName}`
// Every other property within in the target has the form `target.${targetName}.${propertyName}
const isTarget = props.propertyKey.split('.').length === 2;
return (
-
+
*/}
{/* */}
{/**/}
-
+
{isTarget ? 'Created' : 'Set'} by {props.data?.[1]} from{' '}
{props.data?.[0]}
diff --git a/graph/ui-project-details/src/lib/target-configuration-details/target-configuration-details.tsx b/graph/ui-project-details/src/lib/target-configuration-details/target-configuration-details.tsx
index af52a4e54c..c2554e87f7 100644
--- a/graph/ui-project-details/src/lib/target-configuration-details/target-configuration-details.tsx
+++ b/graph/ui-project-details/src/lib/target-configuration-details/target-configuration-details.tsx
@@ -4,7 +4,9 @@ import {
ChevronDownIcon,
ChevronUpIcon,
EyeIcon,
+ InformationCircleIcon,
PlayIcon,
+ QuestionMarkCircleIcon,
} from '@heroicons/react/24/outline';
// nx-ignore-next-line
@@ -31,6 +33,7 @@ import {
} from '@nx/graph/ui-tooltips';
import { TooltipTriggerText } from './tooltip-trigger-text';
import { twMerge } from 'tailwind-merge';
+import { Pill } from '../pill';
/* eslint-disable-next-line */
export interface TargetProps {
@@ -140,40 +143,43 @@ export const TargetConfigurationDetails = forwardRef(
: true);
return (
-
+
-
-
-
{targetName}
- {collapsed && (
-
- {singleCommand ? singleCommand : targetConfiguration.executor}
-
+
+
+ {collapsed ? (
+
+ ) : (
+
)}
-
-
- {onViewInTaskGraph && (
-
{
- e.stopPropagation();
- onViewInTaskGraph({ projectName, targetName });
- }}
- />
+ {targetName}
+ {collapsed &&
+ targetConfiguration?.executor !== '@nx/js:release-publish' && (
+
+ {singleCommand
+ ? singleCommand
+ : targetConfiguration.executor}
+
+ )}
+ {targetName === 'nx-release-publish' && (
+ ) as any}
+ >
+
+
+
+
)}
{targetConfiguration.cache && (
) as any}
>
-
- Cacheable
+
+
)}
- {onRunTarget && (
- {
- e.stopPropagation();
- onRunTarget({ projectName, targetName });
- }}
- />
+
+
+ {onViewInTaskGraph && (
+
)}
- {collapsed ? (
-
- ) : (
-
+
+ {onRunTarget && (
+
+ {
+ e.stopPropagation();
+ onRunTarget({ projectName, targetName });
+ }}
+ />
+
)}
{!collapsed && (
-
-
+
+
-
- nx run {projectName}:{targetName}
-
-
-
- handleCopyClick(`nx run ${projectName}:${targetName}`)
- }
- />
-
+ {targetName !== 'nx-release-publish' && (
+
+
+ nx run {projectName}:{targetName}
+
+
+
+ handleCopyClick(`nx run ${projectName}:${targetName}`)
+ }
+ tooltipAlignment="right"
+ />
+
+
+ )}
)}
@@ -229,7 +262,7 @@ export const TargetConfigurationDetails = forwardRef(
{singleCommand ? (
-
+
Command
) as any}
>
-
+
Executor
@@ -252,15 +285,16 @@ export const TargetConfigurationDetails = forwardRef(
{executorLink ? (
-
+
+
+
) : singleCommand ? (
singleCommand
) : (
@@ -276,7 +310,7 @@ export const TargetConfigurationDetails = forwardRef(
openAction="hover"
content={() as any}
>
-
+
Inputs
@@ -305,7 +339,7 @@ export const TargetConfigurationDetails = forwardRef(
>
{sourceInfo && (
-
+
) as any}
>
-
+
Outputs
@@ -355,7 +389,7 @@ export const TargetConfigurationDetails = forwardRef(
>
{sourceInfo && (
-
+
) as any}
>
-
+
Depends On
-
+
handleCopyClick(
@@ -405,7 +439,7 @@ export const TargetConfigurationDetails = forwardRef(
key={`dependsOn-${idx}`}
>
-
+
{sourceInfo && (
) as any}
>
-
+
Options
@@ -443,7 +477,7 @@ export const TargetConfigurationDetails = forwardRef(
`targets.${targetName}.options.${propertyName}`
);
return sourceInfo ? (
-
+
) as any
}
>
-
+
Configurations
{' '}
{targetConfiguration.defaultConfiguration && (
-
- {targetConfiguration.defaultConfiguration}
+
+
)}
@@ -490,7 +525,7 @@ export const TargetConfigurationDetails = forwardRef(
`targets.${targetName}.configurations.${propertyName}`
);
return sourceInfo ? (
-
+
+
{data}
{children}
@@ -20,7 +20,7 @@ export function TargetConfigurationProperty({
return (
{data.map((item, index) => (
- -
+
-
{String(item)}
{children}
@@ -31,7 +31,7 @@ export function TargetConfigurationProperty({
return (
{Object.entries(data).map(([key, value], index) => (
- -
+
-
{key}: {String(value)}
{children}
diff --git a/graph/ui-project-details/src/lib/target-configuration-details/tooltip-trigger-text.tsx b/graph/ui-project-details/src/lib/target-configuration-details/tooltip-trigger-text.tsx
index fe723255c3..00db47c31b 100644
--- a/graph/ui-project-details/src/lib/target-configuration-details/tooltip-trigger-text.tsx
+++ b/graph/ui-project-details/src/lib/target-configuration-details/tooltip-trigger-text.tsx
@@ -6,7 +6,7 @@ export function TooltipTriggerText({
children: string | ReactNode;
}) {
return (
-
+
{children}
);
diff --git a/graph/ui-tooltips/src/lib/external-link.tsx b/graph/ui-tooltips/src/lib/external-link.tsx
index 31139ede8d..ebc01e5e41 100644
--- a/graph/ui-tooltips/src/lib/external-link.tsx
+++ b/graph/ui-tooltips/src/lib/external-link.tsx
@@ -13,7 +13,7 @@ export function ExternalLink({
{text}
diff --git a/graph/ui-tooltips/src/lib/property-info-tooltip.tsx b/graph/ui-tooltips/src/lib/property-info-tooltip.tsx
index f0aea6e0f4..55a544a443 100644
--- a/graph/ui-tooltips/src/lib/property-info-tooltip.tsx
+++ b/graph/ui-tooltips/src/lib/property-info-tooltip.tsx
@@ -8,7 +8,8 @@ type PropertyInfoTooltipType =
| 'outputs'
| 'dependsOn'
| 'options'
- | 'configurations';
+ | 'configurations'
+ | 'release';
type PropertyInfoTooltipTypeOptions = {
docsUrl: string;
@@ -73,6 +74,12 @@ const PROPERTY_INFO_TOOLTIP_TYPE_OPTIONS: Record<
description:
'Configurations are sets of Options to allow a Target to be used in different scenarios.',
},
+ release: {
+ heading: 'nx release',
+ description:
+ "The nx-release-publish target is used to publish your project with nxrelease. Don't invoke this directly - use nx release publish instead.",
+ docsUrl: 'https://nx.dev/nx-api/nx/documents/release',
+ },
};
export function PropertyInfoTooltip({ type }: PropertyInfoTooltipProps) {
@@ -80,10 +87,10 @@ export function PropertyInfoTooltip({ type }: PropertyInfoTooltipProps) {
return (
-
+
{propertyInfo.heading}
-
+
{propertyInfo.description}
diff --git a/graph/ui-tooltips/src/lib/sourcemap-info-tooltip.tsx b/graph/ui-tooltips/src/lib/sourcemap-info-tooltip.tsx
index d9a3556322..b31c23a027 100644
--- a/graph/ui-tooltips/src/lib/sourcemap-info-tooltip.tsx
+++ b/graph/ui-tooltips/src/lib/sourcemap-info-tooltip.tsx
@@ -24,7 +24,7 @@ export function SourcemapInfoToolTip({
return (
-
+
{isTarget ? 'Created' : 'Set'} by:
diff --git a/graph/ui-tooltips/src/lib/tooltip.tsx b/graph/ui-tooltips/src/lib/tooltip.tsx
index eb3b704e05..916865b0f4 100644
--- a/graph/ui-tooltips/src/lib/tooltip.tsx
+++ b/graph/ui-tooltips/src/lib/tooltip.tsx
@@ -26,6 +26,7 @@ import {
useHover,
useRole,
safePolygon,
+ useTransitionStyles,
} from '@floating-ui/react';
export type TooltipProps = HTMLAttributes & {
@@ -76,6 +77,13 @@ export function Tooltip({
],
});
+ const { isMounted, styles: animationStyles } = useTransitionStyles(context, {
+ duration: 200,
+ initial: {
+ opacity: openAction === 'hover' ? 0 : 1,
+ },
+ });
+
const staticSide: string =
{
top: 'bottom',
@@ -98,6 +106,7 @@ export function Tooltip({
outsidePressEvent: 'mousedown',
});
const hover = useHover(context, {
+ restMs: 300,
enabled: openAction === 'hover',
delay: { open: 0, close: 150 },
handleClose: safePolygon({ buffer }),
@@ -121,7 +130,7 @@ export function Tooltip({
{!externalReference && !!children
? cloneElement(children, cloneProps)
: children}
- {isOpen ? (
+ {isOpen && isMounted ? (