Skip to content

Commit

Permalink
feat(graph): show script content in header (#23257)
Browse files Browse the repository at this point in the history
<!-- 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
-->
![Screenshot 2024-05-15 at 10 32
54 AM](https://github.com/nrwl/nx/assets/16211801/1ef4d67f-94e5-46bd-bcee-b966984e86cd)

<img width="1023" alt="Screenshot 2024-05-08 at 5 53 06 PM"
src="https://github.com/nrwl/nx/assets/16211801/cb9161bd-fc4a-4965-89f7-09ce8d72226e">

<img width="585" alt="Screenshot 2024-05-08 at 5 52 51 PM"
src="https://github.com/nrwl/nx/assets/16211801/760ebe19-1c29-4fad-ba9d-174b8303a362">


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

Fixes #
  • Loading branch information
xiongemi authored May 21, 2024
1 parent 992ae85 commit 08ef0e4
Show file tree
Hide file tree
Showing 18 changed files with 407 additions and 130 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { Pill } from '../pill';
import { TargetTechnologies } from '../target-technologies/target-technologies';
import { SourceInfo } from '../source-info/source-info';
import { CopyToClipboard } from '../copy-to-clipboard/copy-to-clipboard';
import { getDisplayHeaderFromTargetConfiguration } from '../utils/get-display-header-from-target-configuration';
import { TargetExecutor } from '../target-executor/target-executor';

export interface TargetConfigurationDetailsHeaderProps {
isCollasped: boolean;
Expand Down Expand Up @@ -52,10 +54,8 @@ export const TargetConfigurationDetailsHeader = ({
isCollasped = false;
}

const singleCommand =
targetConfiguration.executor === 'nx:run-commands'
? targetConfiguration.command ?? targetConfiguration.options?.command
: null;
const { command, commands, script, executor } =
getDisplayHeaderFromTargetConfiguration(targetConfiguration);

return (
<header
Expand Down Expand Up @@ -86,7 +86,13 @@ export const TargetConfigurationDetailsHeader = ({
{isCollasped &&
targetConfiguration?.executor !== '@nx/js:release-publish' && (
<p className="min-w-0 flex-1 truncate text-sm text-slate-400">
{singleCommand ? singleCommand : targetConfiguration.executor}
<TargetExecutor
command={command}
commands={commands}
script={script}
executor={executor}
isCompact={true}
/>
</p>
)}
{targetName === 'nx-release-publish' && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,20 @@
import type { TargetConfiguration } from '@nx/devkit';

import { JsonCodeBlock } from '@nx/graph/ui-code-block';
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useCallback, useContext, useEffect, useState } from 'react';
import { SourceInfo } from '../source-info/source-info';
import { FadingCollapsible } from './fading-collapsible';
import { TargetConfigurationProperty } from './target-configuration-property';
import { selectSourceInfo } from './target-configuration-details.util';
import { CopyToClipboard } from '../copy-to-clipboard/copy-to-clipboard';
import {
ExternalLink,
PropertyInfoTooltip,
Tooltip,
} from '@nx/graph/ui-tooltips';
import { PropertyInfoTooltip, Tooltip } from '@nx/graph/ui-tooltips';
import { TooltipTriggerText } from './tooltip-trigger-text';
import { Pill } from '../pill';
import { TargetConfigurationDetailsHeader } from '../target-configuration-details-header/target-configuration-details-header';
import { ExpandedTargetsContext } from '@nx/graph/shared';
import { getDisplayHeaderFromTargetConfiguration } from '../utils/get-display-header-from-target-configuration';
import { TargetExecutor } from '../target-executor/target-executor';
import { TargetExecutorTitle } from '../target-executor/target-executor-title';

interface TargetConfigurationDetailsProps {
projectName: string;
Expand Down Expand Up @@ -71,36 +70,8 @@ export default function TargetConfigurationDetails({
}
}, [expandedTargets, targetName, collapsable]);

let executorLink: string | null = null;

// TODO: Handle this better because this will not work with labs
if (targetConfiguration.executor?.startsWith('@nx/')) {
const packageName = targetConfiguration.executor
.split('/')[1]
.split(':')[0];
const executorName = targetConfiguration.executor
.split('/')[1]
.split(':')[1];
executorLink = `https://nx.dev/nx-api/${packageName}/executors/${executorName}`;
} else if (targetConfiguration.executor === 'nx:run-commands') {
executorLink = `https://nx.dev/nx-api/nx/executors/run-commands`;
} else if (targetConfiguration.executor === 'nx:run-script') {
executorLink = `https://nx.dev/nx-api/nx/executors/run-script`;
}

const singleCommand =
targetConfiguration.executor === 'nx:run-commands'
? targetConfiguration.command ?? targetConfiguration.options?.command
: null;
const options = useMemo(() => {
if (singleCommand) {
const { command, ...rest } = targetConfiguration.options;
return rest;
} else {
return targetConfiguration.options;
}
}, [targetConfiguration.options, singleCommand]);

const { link, options, script, ...displayHeader } =
getDisplayHeaderFromTargetConfiguration(targetConfiguration);
const configurations = targetConfiguration.configurations;

const shouldRenderOptions =
Expand Down Expand Up @@ -132,48 +103,30 @@ export default function TargetConfigurationDetails({
<div className="p-4 text-base">
<div className="group mb-4">
<h4 className="mb-4">
{singleCommand ? (
<span className="font-medium">
Command
<span className="mb-1 ml-2 hidden group-hover:inline">
<CopyToClipboard
onCopy={() =>
handleCopyClick(`"command": "${singleCommand}"`)
}
/>
</span>
</span>
) : (
<Tooltip
openAction="hover"
content={(<PropertyInfoTooltip type="executors" />) as any}
>
<span className="font-medium">
<TooltipTriggerText>Executor</TooltipTriggerText>
</span>
</Tooltip>
)}
<TargetExecutorTitle
{...displayHeader}
handleCopyClick={handleCopyClick}
/>
</h4>
<p className="pl-5 font-mono">
{executorLink ? (
<span>
<ExternalLink
href={executorLink ?? 'https://nx.dev/nx-api'}
text={
singleCommand
? singleCommand
: targetConfiguration.executor
}
/>
</span>
) : singleCommand ? (
singleCommand
) : (
targetConfiguration.executor
)}
<TargetExecutor {...displayHeader} link={link} />
</p>
</div>

{script && (
<div className="group mb-4">
<h4 className="mb-4">
<TargetExecutorTitle
script={script}
handleCopyClick={handleCopyClick}
/>
</h4>
<p className="pl-5 font-mono">
<TargetExecutor script={script} link={link} />
</p>
</div>
)}

{targetConfiguration.inputs && (
<div className="group">
<h4 className="mb-4">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { Meta, StoryObj } from '@storybook/react';
import { TargetExecutorTitle } from './target-executor-title';

const meta: Meta<typeof TargetExecutorTitle> = {
component: TargetExecutorTitle,
title: 'TargetExecutorTitle',
};
export default meta;

type Story = StoryObj<typeof TargetExecutorTitle>;

export const Command: Story = {
args: {
command: 'nx run my-app:build',
},
};

export const Commands: Story = {
args: {
commands: ['nx run my-app:build', 'nx run my-app:test'],
},
};

export const Script: Story = {
args: {
script: 'nx run my-app:build',
},
};

export const Executor: Story = {
args: {},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { PropertyInfoTooltip, Tooltip } from '@nx/graph/ui-tooltips';
import { CopyToClipboard } from '../copy-to-clipboard/copy-to-clipboard';
import { TooltipTriggerText } from '../target-configuration-details/tooltip-trigger-text';

export function TargetExecutorTitle({
commands,
command,
script,
handleCopyClick,
}: {
handleCopyClick: (copyText: string) => void;
commands?: string[];
command?: string;
script?: string;
}) {
if (commands && commands.length) {
return (
<span className="font-medium">
Commands
<span className="mb-1 ml-2 hidden group-hover:inline">
<CopyToClipboard
onCopy={() =>
handleCopyClick(
`"commands": [${commands.map((c) => `"${c}"`).join(', ')}]`
)
}
/>
</span>
</span>
);
}
if (command) {
return (
<span className="font-medium">
Command
<span className="mb-1 ml-2 hidden group-hover:inline">
<CopyToClipboard
onCopy={() => handleCopyClick(`"command": "${command}"`)}
/>
</span>
</span>
);
}
if (script) {
return (
<span className="font-medium">
Script
<span className="mb-1 ml-2 hidden group-hover:inline">
<CopyToClipboard onCopy={() => handleCopyClick(script)} />
</span>
</span>
);
}
return (
<Tooltip
openAction="hover"
content={(<PropertyInfoTooltip type="executors" />) as any}
>
<span className="font-medium">
<TooltipTriggerText>Executor</TooltipTriggerText>
</span>
</Tooltip>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import type { Meta, StoryObj } from '@storybook/react';
import { TargetExecutor } from './target-executor';

const meta: Meta<typeof TargetExecutor> = {
component: TargetExecutor,
title: 'TargetExecutor',
};
export default meta;

type Story = StoryObj<typeof TargetExecutor>;

export const Command: Story = {
args: {
command: 'nx run my-app:build',
},
};

export const Commands: Story = {
args: {
commands: ['nx run my-app:build', 'nx run my-app:test'],
},
};

export const Script: Story = {
args: {
script: 'nx run my-app:build',
},
};

export const Executor: Story = {
args: {
executor: 'nx run my-app:build',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ExternalLink } from '@nx/graph/ui-tooltips';

export interface TargetExecutorProps {
command?: string;
commands?: string[];
script?: string;
executor?: string;
isCompact?: boolean;
link?: string;
}

export function TargetExecutor({
command,
commands,
script,
executor,
isCompact,
link,
}: TargetExecutorProps) {
if (commands) {
if (isCompact) {
return link ? (
<ExternalLink href={link}>
{commands.length === 1 ? commands[0] : executor}
</ExternalLink>
) : commands.length === 1 ? (
commands[0]
) : (
executor
);
}
return (
<ul>
{commands?.map((c) =>
c ? (
<li>{link ? <ExternalLink href={link}>{c}</ExternalLink> : c}</li>
) : null
)}
</ul>
);
}

const displayText = command ?? script ?? executor ?? '';
return link ? (
<ExternalLink href={link}>{displayText}</ExternalLink>
) : (
displayText
);
}
Loading

0 comments on commit 08ef0e4

Please sign in to comment.