feat(graph): add atomizer label to target groups (#26622)
## Current Behavior Atomized Groups are treated just like any other groups in the PDV ## Expected Behavior We want to let people know that something was created by the Atomizer and also surface more information to users.
This commit is contained in:
parent
ce3f7f4ed8
commit
6528da3bd8
@ -25,40 +25,10 @@ export class ExternalApiImpl extends ExternalApi {
|
|||||||
console.log('graphInteractionEventListener not registered.');
|
console.log('graphInteractionEventListener not registered.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type === 'file-click') {
|
this.graphInteractionEventListener({
|
||||||
const url = `${payload.sourceRoot}/${payload.file}`;
|
type,
|
||||||
this.graphInteractionEventListener({
|
payload,
|
||||||
type: 'file-click',
|
});
|
||||||
payload: { url },
|
|
||||||
});
|
|
||||||
} else if (type === 'open-project-config') {
|
|
||||||
this.graphInteractionEventListener({
|
|
||||||
type: 'open-project-config',
|
|
||||||
payload,
|
|
||||||
});
|
|
||||||
} else if (type === 'run-task') {
|
|
||||||
this.graphInteractionEventListener({
|
|
||||||
type: 'run-task',
|
|
||||||
payload,
|
|
||||||
});
|
|
||||||
} else if (type === 'open-project-graph') {
|
|
||||||
this.graphInteractionEventListener({
|
|
||||||
type: 'open-project-graph',
|
|
||||||
payload,
|
|
||||||
});
|
|
||||||
} else if (type === 'open-task-graph') {
|
|
||||||
this.graphInteractionEventListener({
|
|
||||||
type: 'open-task-graph',
|
|
||||||
payload,
|
|
||||||
});
|
|
||||||
} else if (type === 'override-target') {
|
|
||||||
this.graphInteractionEventListener({
|
|
||||||
type: 'override-target',
|
|
||||||
payload,
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log('unhandled event', type, payload);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -83,6 +83,7 @@ const projectDetailsLoader = async (
|
|||||||
project: ProjectGraphProjectNode;
|
project: ProjectGraphProjectNode;
|
||||||
sourceMap: Record<string, string[]>;
|
sourceMap: Record<string, string[]>;
|
||||||
errors?: GraphError[];
|
errors?: GraphError[];
|
||||||
|
connectedToCloud?: boolean;
|
||||||
}> => {
|
}> => {
|
||||||
const workspaceData = await workspaceDataLoader(selectedWorkspaceId);
|
const workspaceData = await workspaceDataLoader(selectedWorkspaceId);
|
||||||
const sourceMaps = await sourceMapsLoader(selectedWorkspaceId);
|
const sourceMaps = await sourceMapsLoader(selectedWorkspaceId);
|
||||||
@ -102,6 +103,7 @@ const projectDetailsLoader = async (
|
|||||||
project,
|
project,
|
||||||
sourceMap: sourceMaps[project.data.root],
|
sourceMap: sourceMaps[project.data.root],
|
||||||
errors: workspaceData.errors,
|
errors: workspaceData.errors,
|
||||||
|
connectedToCloud: workspaceData.connectedToCloud,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -69,8 +69,7 @@ export function TooltipDisplay() {
|
|||||||
externalApiService.postEvent({
|
externalApiService.postEvent({
|
||||||
type: 'file-click',
|
type: 'file-click',
|
||||||
payload: {
|
payload: {
|
||||||
sourceRoot: currentTooltip.props.sourceRoot,
|
url: `${currentTooltip.props.sourceRoot}/${url}`,
|
||||||
file: url,
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|||||||
@ -21,14 +21,14 @@ import {
|
|||||||
import { ProjectDetailsHeader } from './project-details-header';
|
import { ProjectDetailsHeader } from './project-details-header';
|
||||||
|
|
||||||
export function ProjectDetailsPage() {
|
export function ProjectDetailsPage() {
|
||||||
const { project, sourceMap, hash, errors } = useRouteLoaderData(
|
const { project, sourceMap, hash, errors, connectedToCloud } =
|
||||||
'selectedProjectDetails'
|
useRouteLoaderData('selectedProjectDetails') as {
|
||||||
) as {
|
hash: string;
|
||||||
hash: string;
|
project: ProjectGraphProjectNode;
|
||||||
project: ProjectGraphProjectNode;
|
sourceMap: Record<string, string[]>;
|
||||||
sourceMap: Record<string, string[]>;
|
errors?: GraphError[];
|
||||||
errors?: GraphError[];
|
connectedToCloud?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
const { environment, watch, appConfig } = useEnvironmentConfig();
|
const { environment, watch, appConfig } = useEnvironmentConfig();
|
||||||
|
|
||||||
@ -64,6 +64,7 @@ export function ProjectDetailsPage() {
|
|||||||
project={project}
|
project={project}
|
||||||
sourceMap={sourceMap}
|
sourceMap={sourceMap}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
|
connectedToCloud={connectedToCloud}
|
||||||
></ProjectDetailsWrapper>
|
></ProjectDetailsWrapper>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -21,12 +21,14 @@ interface ProjectDetailsProps {
|
|||||||
project: ProjectGraphProjectNode;
|
project: ProjectGraphProjectNode;
|
||||||
sourceMap: Record<string, string[]>;
|
sourceMap: Record<string, string[]>;
|
||||||
errors?: GraphError[];
|
errors?: GraphError[];
|
||||||
|
connectedToCloud?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ProjectDetailsWrapper({
|
export function ProjectDetailsWrapper({
|
||||||
project,
|
project,
|
||||||
sourceMap,
|
sourceMap,
|
||||||
errors,
|
errors,
|
||||||
|
connectedToCloud,
|
||||||
}: ProjectDetailsProps) {
|
}: ProjectDetailsProps) {
|
||||||
const environment = useEnvironmentConfig()?.environment;
|
const environment = useEnvironmentConfig()?.environment;
|
||||||
const externalApiService = getExternalApiService();
|
const externalApiService = getExternalApiService();
|
||||||
@ -95,6 +97,14 @@ export function ProjectDetailsWrapper({
|
|||||||
[externalApiService]
|
[externalApiService]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleNxConnect = useCallback(
|
||||||
|
() =>
|
||||||
|
externalApiService.postEvent({
|
||||||
|
type: 'nx-connect',
|
||||||
|
}),
|
||||||
|
[externalApiService]
|
||||||
|
);
|
||||||
|
|
||||||
const updateSearchParams = (
|
const updateSearchParams = (
|
||||||
params: URLSearchParams,
|
params: URLSearchParams,
|
||||||
targetNames?: string[]
|
targetNames?: string[]
|
||||||
@ -162,6 +172,10 @@ export function ProjectDetailsWrapper({
|
|||||||
viewInProjectGraphPosition={
|
viewInProjectGraphPosition={
|
||||||
environment === 'nx-console' ? 'bottom' : 'top'
|
environment === 'nx-console' ? 'bottom' : 'top'
|
||||||
}
|
}
|
||||||
|
connectedToCloud={connectedToCloud}
|
||||||
|
nxConnectCallback={
|
||||||
|
environment === 'nx-console' ? handleNxConnect : undefined
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<ErrorToast errors={errors} />
|
<ErrorToast errors={errors} />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -9,10 +9,10 @@ export function getExternalApiService() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ExternalApiService {
|
export class ExternalApiService {
|
||||||
private subscribers: Set<(event: { type: string; payload: any }) => void> =
|
private subscribers: Set<(event: { type: string; payload?: any }) => void> =
|
||||||
new Set();
|
new Set();
|
||||||
|
|
||||||
postEvent(event: { type: string; payload: any }) {
|
postEvent(event: { type: string; payload?: any }) {
|
||||||
this.subscribers.forEach((subscriber) => {
|
this.subscribers.forEach((subscriber) => {
|
||||||
subscriber(event);
|
subscriber(event);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './lib/technology-icon';
|
export * from './lib/technology-icon';
|
||||||
export * from './lib/framework-icons';
|
export * from './lib/framework-icons';
|
||||||
|
export * from './lib/ nx-cloud-icon';
|
||||||
|
|||||||
17
graph/ui-icons/src/lib/ nx-cloud-icon.tsx
Normal file
17
graph/ui-icons/src/lib/ nx-cloud-icon.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
import { FC, SVGProps } from 'react';
|
||||||
|
|
||||||
|
export const NxCloudIcon: FC<SVGProps<SVGSVGElement>> = (props) => (
|
||||||
|
<svg
|
||||||
|
role="img"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
stroke="currentColor"
|
||||||
|
fill="transparent"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
d="M22.167 7.167v-2.5a2.5 2.5 0 0 0-2.5-2.5h-15a2.5 2.5 0 0 0-2.5 2.5v15a2.5 2.5 0 0 0 2.5 2.5h2.5m15-15c-2.76 0-5 2.24-5 5s-2.24 5-5 5-5 2.24-5 5m15-15V19.59a2.577 2.577 0 0 1-2.576 2.576H7.167"
|
||||||
|
strokeWidth="2"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
@ -19,12 +19,14 @@ export interface ProjectDetailsProps {
|
|||||||
sourceMap: Record<string, string[]>;
|
sourceMap: Record<string, string[]>;
|
||||||
errors?: GraphError[];
|
errors?: GraphError[];
|
||||||
variant?: 'default' | 'compact';
|
variant?: 'default' | 'compact';
|
||||||
|
connectedToCloud?: boolean;
|
||||||
onViewInProjectGraph?: (data: { projectName: string }) => void;
|
onViewInProjectGraph?: (data: { projectName: string }) => void;
|
||||||
onViewInTaskGraph?: (data: {
|
onViewInTaskGraph?: (data: {
|
||||||
projectName: string;
|
projectName: string;
|
||||||
targetName: string;
|
targetName: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
onRunTarget?: (data: { projectName: string; targetName: string }) => void;
|
onRunTarget?: (data: { projectName: string; targetName: string }) => void;
|
||||||
|
nxConnectCallback?: () => void;
|
||||||
viewInProjectGraphPosition?: 'top' | 'bottom';
|
viewInProjectGraphPosition?: 'top' | 'bottom';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +43,9 @@ export const ProjectDetails = ({
|
|||||||
onViewInProjectGraph,
|
onViewInProjectGraph,
|
||||||
onViewInTaskGraph,
|
onViewInTaskGraph,
|
||||||
onRunTarget,
|
onRunTarget,
|
||||||
|
nxConnectCallback,
|
||||||
viewInProjectGraphPosition = 'top',
|
viewInProjectGraphPosition = 'top',
|
||||||
|
connectedToCloud,
|
||||||
}: ProjectDetailsProps) => {
|
}: ProjectDetailsProps) => {
|
||||||
const projectData = project.data;
|
const projectData = project.data;
|
||||||
const isCompact = variant === 'compact';
|
const isCompact = variant === 'compact';
|
||||||
@ -161,6 +165,8 @@ export const ProjectDetails = ({
|
|||||||
variant={variant}
|
variant={variant}
|
||||||
onRunTarget={onRunTarget}
|
onRunTarget={onRunTarget}
|
||||||
onViewInTaskGraph={onViewInTaskGraph}
|
onViewInTaskGraph={onViewInTaskGraph}
|
||||||
|
connectedToCloud={connectedToCloud}
|
||||||
|
nxConnectCallback={nxConnectCallback}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@ -3,12 +3,18 @@ import { TargetConfigurationGroupHeader } from '../target-configuration-details-
|
|||||||
export interface TargetConfigurationGroupContainerProps {
|
export interface TargetConfigurationGroupContainerProps {
|
||||||
targetGroupName: string;
|
targetGroupName: string;
|
||||||
targetsNumber: number;
|
targetsNumber: number;
|
||||||
|
nonAtomizedTarget?: string;
|
||||||
|
connectedToCloud?: boolean;
|
||||||
|
nxConnectCallback?: () => void;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TargetConfigurationGroupContainer({
|
export function TargetConfigurationGroupContainer({
|
||||||
targetGroupName,
|
targetGroupName,
|
||||||
targetsNumber,
|
targetsNumber,
|
||||||
|
nonAtomizedTarget,
|
||||||
|
connectedToCloud,
|
||||||
|
nxConnectCallback,
|
||||||
children,
|
children,
|
||||||
}: TargetConfigurationGroupContainerProps) {
|
}: TargetConfigurationGroupContainerProps) {
|
||||||
return (
|
return (
|
||||||
@ -16,6 +22,9 @@ export function TargetConfigurationGroupContainer({
|
|||||||
<TargetConfigurationGroupHeader
|
<TargetConfigurationGroupHeader
|
||||||
targetGroupName={targetGroupName}
|
targetGroupName={targetGroupName}
|
||||||
targetsNumber={targetsNumber}
|
targetsNumber={targetsNumber}
|
||||||
|
nonAtomizedTarget={nonAtomizedTarget}
|
||||||
|
connectedToCloud={connectedToCloud}
|
||||||
|
nxConnectCallback={nxConnectCallback}
|
||||||
className="sticky top-0 z-10 bg-white dark:bg-slate-900"
|
className="sticky top-0 z-10 bg-white dark:bg-slate-900"
|
||||||
/>
|
/>
|
||||||
<div className="rounded-md border border-slate-200 p-2 dark:border-slate-700">
|
<div className="rounded-md border border-slate-200 p-2 dark:border-slate-700">
|
||||||
|
|||||||
@ -15,3 +15,21 @@ export const Simple: Story = {
|
|||||||
targetsNumber: 5,
|
targetsNumber: 5,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const AtomizerCloud: Story = {
|
||||||
|
args: {
|
||||||
|
targetGroupName: 'Target Group Name',
|
||||||
|
targetsNumber: 5,
|
||||||
|
nonAtomizedTarget: 'e2e',
|
||||||
|
connectedToCloud: true,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AtomizerNoCloud: Story = {
|
||||||
|
args: {
|
||||||
|
targetGroupName: 'Target Group Name',
|
||||||
|
targetsNumber: 5,
|
||||||
|
nonAtomizedTarget: 'e2e',
|
||||||
|
connectedToCloud: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|||||||
@ -1,25 +1,60 @@
|
|||||||
|
import { AtomizerTooltip, Tooltip } from '@nx/graph/ui-tooltips';
|
||||||
import { Pill } from '../pill';
|
import { Pill } from '../pill';
|
||||||
|
import { Square3Stack3DIcon } from '@heroicons/react/24/outline';
|
||||||
|
|
||||||
export interface TargetConfigurationGroupHeaderProps {
|
export interface TargetConfigurationGroupHeaderProps {
|
||||||
targetGroupName: string;
|
targetGroupName: string;
|
||||||
targetsNumber: number;
|
targetsNumber: number;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
nonAtomizedTarget?: string;
|
||||||
|
connectedToCloud?: boolean;
|
||||||
|
nxConnectCallback?: () => void;
|
||||||
|
showIcon?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TargetConfigurationGroupHeader = ({
|
export const TargetConfigurationGroupHeader = ({
|
||||||
targetGroupName,
|
targetGroupName,
|
||||||
targetsNumber,
|
targetsNumber,
|
||||||
|
nonAtomizedTarget,
|
||||||
|
connectedToCloud = true,
|
||||||
|
nxConnectCallback,
|
||||||
className = '',
|
className = '',
|
||||||
}: TargetConfigurationGroupHeaderProps) => {
|
}: TargetConfigurationGroupHeaderProps) => {
|
||||||
return (
|
return (
|
||||||
<header className={`px-4 py-2 text-lg capitalize ${className}`}>
|
<header
|
||||||
|
className={`flex items-center gap-2 px-4 py-2 text-lg capitalize ${className}`}
|
||||||
|
>
|
||||||
{targetGroupName}{' '}
|
{targetGroupName}{' '}
|
||||||
|
{nonAtomizedTarget && <Square3Stack3DIcon className="h-5 w-5" />}
|
||||||
<Pill
|
<Pill
|
||||||
text={
|
text={
|
||||||
targetsNumber.toString() +
|
targetsNumber.toString() +
|
||||||
(targetsNumber === 1 ? ' target' : ' targets')
|
(targetsNumber === 1 ? ' target' : ' targets')
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{nonAtomizedTarget && (
|
||||||
|
<Tooltip
|
||||||
|
openAction="hover"
|
||||||
|
strategy="fixed"
|
||||||
|
usePortal={true}
|
||||||
|
content={
|
||||||
|
(
|
||||||
|
<AtomizerTooltip
|
||||||
|
connectedToCloud={connectedToCloud}
|
||||||
|
nonAtomizedTarget={nonAtomizedTarget}
|
||||||
|
nxConnectCallback={nxConnectCallback}
|
||||||
|
/>
|
||||||
|
) as any
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="inline-flex">
|
||||||
|
<Pill
|
||||||
|
color={connectedToCloud ? 'grey' : 'yellow'}
|
||||||
|
text={'Atomizer'}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
</header>
|
</header>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,7 +4,10 @@ import type { ProjectGraphProjectNode } from '@nx/devkit';
|
|||||||
|
|
||||||
import { TargetConfigurationDetailsListItem } from '../target-configuration-details-list-item/target-configuration-details-list-item';
|
import { TargetConfigurationDetailsListItem } from '../target-configuration-details-list-item/target-configuration-details-list-item';
|
||||||
import { TargetConfigurationGroupContainer } from '../target-configuration-details-group-container/target-configuration-details-group-container';
|
import { TargetConfigurationGroupContainer } from '../target-configuration-details-group-container/target-configuration-details-group-container';
|
||||||
import { groupTargets } from '../utils/group-targets';
|
import {
|
||||||
|
getNonAtomizedTargetForGroup,
|
||||||
|
groupTargets,
|
||||||
|
} from '../utils/group-targets';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export interface TargetConfigurationGroupListProps {
|
export interface TargetConfigurationGroupListProps {
|
||||||
@ -16,6 +19,8 @@ export interface TargetConfigurationGroupListProps {
|
|||||||
projectName: string;
|
projectName: string;
|
||||||
targetName: string;
|
targetName: string;
|
||||||
}) => void;
|
}) => void;
|
||||||
|
nxConnectCallback?: () => void;
|
||||||
|
connectedToCloud?: boolean;
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +30,9 @@ export function TargetConfigurationGroupList({
|
|||||||
sourceMap,
|
sourceMap,
|
||||||
onRunTarget,
|
onRunTarget,
|
||||||
onViewInTaskGraph,
|
onViewInTaskGraph,
|
||||||
|
nxConnectCallback,
|
||||||
className = '',
|
className = '',
|
||||||
|
connectedToCloud,
|
||||||
}: TargetConfigurationGroupListProps) {
|
}: TargetConfigurationGroupListProps) {
|
||||||
const targetsGroup = useMemo(() => groupTargets(project), [project]);
|
const targetsGroup = useMemo(() => groupTargets(project), [project]);
|
||||||
const hasGroups = useMemo(() => {
|
const hasGroups = useMemo(() => {
|
||||||
@ -47,6 +54,12 @@ export function TargetConfigurationGroupList({
|
|||||||
<TargetConfigurationGroupContainer
|
<TargetConfigurationGroupContainer
|
||||||
targetGroupName={targetGroupName}
|
targetGroupName={targetGroupName}
|
||||||
targetsNumber={targets.length}
|
targetsNumber={targets.length}
|
||||||
|
nonAtomizedTarget={getNonAtomizedTargetForGroup(
|
||||||
|
project,
|
||||||
|
targetGroupName
|
||||||
|
)}
|
||||||
|
connectedToCloud={connectedToCloud}
|
||||||
|
nxConnectCallback={nxConnectCallback}
|
||||||
key={targetGroupName}
|
key={targetGroupName}
|
||||||
>
|
>
|
||||||
<ul className={className}>
|
<ul className={className}>
|
||||||
|
|||||||
@ -33,3 +33,18 @@ function sortNxReleasePublishLast(a: string, b: string) {
|
|||||||
if (b === 'nx-release-publish') return -1;
|
if (b === 'nx-release-publish') return -1;
|
||||||
return a.localeCompare(b);
|
return a.localeCompare(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getNonAtomizedTargetForGroup(
|
||||||
|
project: ProjectGraphProjectNode,
|
||||||
|
targetGroupName: string
|
||||||
|
): string | undefined {
|
||||||
|
const targetWithNonAtomizedEquivalent = project.data.metadata?.targetGroups?.[
|
||||||
|
targetGroupName
|
||||||
|
]?.find(
|
||||||
|
(target) => project.data.targets?.[target]?.metadata?.nonAtomizedTarget
|
||||||
|
);
|
||||||
|
return targetWithNonAtomizedEquivalent
|
||||||
|
? project.data.targets?.[targetWithNonAtomizedEquivalent]?.metadata
|
||||||
|
?.nonAtomizedTarget
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|||||||
@ -6,3 +6,4 @@ export * from './lib/tooltip-button';
|
|||||||
export * from './lib/property-info-tooltip';
|
export * from './lib/property-info-tooltip';
|
||||||
export * from './lib/sourcemap-info-tooltip';
|
export * from './lib/sourcemap-info-tooltip';
|
||||||
export * from './lib/external-link';
|
export * from './lib/external-link';
|
||||||
|
export * from './lib/atomizer-tooltip';
|
||||||
|
|||||||
72
graph/ui-tooltips/src/lib/atomizer-tooltip.stories.tsx
Normal file
72
graph/ui-tooltips/src/lib/atomizer-tooltip.stories.tsx
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { AtomizerTooltip, AtomizerTooltipProps } from './atomizer-tooltip';
|
||||||
|
import { Tooltip } from './tooltip';
|
||||||
|
|
||||||
|
const meta: Meta<typeof AtomizerTooltip> = {
|
||||||
|
component: AtomizerTooltip,
|
||||||
|
title: 'Tooltips/AtomizerTooltip',
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof AtomizerTooltip>;
|
||||||
|
|
||||||
|
export const Cloud: Story = {
|
||||||
|
args: {
|
||||||
|
connectedToCloud: true,
|
||||||
|
nonAtomizedTarget: 'e2e',
|
||||||
|
} as AtomizerTooltipProps,
|
||||||
|
render: (args) => {
|
||||||
|
return (
|
||||||
|
<div className="flex w-full justify-center">
|
||||||
|
<Tooltip
|
||||||
|
open={true}
|
||||||
|
openAction="manual"
|
||||||
|
content={(<AtomizerTooltip {...args} />) as any}
|
||||||
|
>
|
||||||
|
<p>Internal Reference</p>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NoCloud: Story = {
|
||||||
|
args: {
|
||||||
|
connectedToCloud: false,
|
||||||
|
nonAtomizedTarget: 'e2e',
|
||||||
|
} as AtomizerTooltipProps,
|
||||||
|
render: (args) => {
|
||||||
|
return (
|
||||||
|
<div className="flex w-full justify-center">
|
||||||
|
<Tooltip
|
||||||
|
open={true}
|
||||||
|
openAction="manual"
|
||||||
|
content={(<AtomizerTooltip {...args} />) as any}
|
||||||
|
>
|
||||||
|
<p>Internal Reference</p>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NoCloudConsole: Story = {
|
||||||
|
args: {
|
||||||
|
connectedToCloud: false,
|
||||||
|
nonAtomizedTarget: 'e2e',
|
||||||
|
nxConnectCallback: () => console.log('nxConnectCallback'),
|
||||||
|
} as AtomizerTooltipProps,
|
||||||
|
render: (args) => {
|
||||||
|
return (
|
||||||
|
<div className="flex w-full justify-center">
|
||||||
|
<Tooltip
|
||||||
|
open={true}
|
||||||
|
openAction="manual"
|
||||||
|
content={(<AtomizerTooltip {...args} />) as any}
|
||||||
|
>
|
||||||
|
<p>Internal Reference</p>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
106
graph/ui-tooltips/src/lib/atomizer-tooltip.tsx
Normal file
106
graph/ui-tooltips/src/lib/atomizer-tooltip.tsx
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import { NxCloudIcon } from '@nx/graph/ui-icons';
|
||||||
|
import { twMerge } from 'tailwind-merge';
|
||||||
|
|
||||||
|
export interface AtomizerTooltipProps {
|
||||||
|
connectedToCloud: boolean;
|
||||||
|
nonAtomizedTarget: string;
|
||||||
|
nxConnectCallback?: () => void;
|
||||||
|
}
|
||||||
|
export function AtomizerTooltip(props: AtomizerTooltipProps) {
|
||||||
|
return (
|
||||||
|
<div className="z-20 max-w-lg text-sm text-slate-700 dark:text-slate-400">
|
||||||
|
<h4 className="flex items-center justify-between border-b border-slate-200 text-base dark:border-slate-700/60">
|
||||||
|
<span className="font-mono">Atomizer</span>
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
className={twMerge(
|
||||||
|
'flex flex-col py-2 font-mono',
|
||||||
|
!props.connectedToCloud
|
||||||
|
? 'border-b border-slate-200 dark:border-slate-700/60'
|
||||||
|
: ''
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<p className="whitespace-pre-wrap normal-case">
|
||||||
|
{'Nx '}
|
||||||
|
<Link
|
||||||
|
href="https://nx.dev/ci/features/split-e2e-tasks"
|
||||||
|
text="automatically split"
|
||||||
|
/>
|
||||||
|
{
|
||||||
|
' this potentially slow task into separate tasks for each file. We recommend enabling '
|
||||||
|
}
|
||||||
|
{!props.connectedToCloud && (
|
||||||
|
<>
|
||||||
|
<Link href="https://nx.app/" text="Nx Cloud" />
|
||||||
|
{' and '}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Link
|
||||||
|
href="https://nx.dev/ci/features/distribute-task-execution"
|
||||||
|
text="Nx Agents"
|
||||||
|
/>
|
||||||
|
{' to benefit from '}
|
||||||
|
<Link
|
||||||
|
href="https://nx.dev/ci/features/distribute-task-execution"
|
||||||
|
text="task distribution"
|
||||||
|
/>
|
||||||
|
{!props.connectedToCloud && (
|
||||||
|
<>
|
||||||
|
{', '}
|
||||||
|
<Link
|
||||||
|
href="https://nx.dev/ci/features/remote-cache"
|
||||||
|
text="remote caching"
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{' and '}
|
||||||
|
<Link
|
||||||
|
href="https://nx.dev/ci/features/flaky-tasks"
|
||||||
|
text="flaky task re-runs"
|
||||||
|
/>
|
||||||
|
. Use
|
||||||
|
<code className="mx-2 inline rounded bg-gray-100 px-1 font-mono text-gray-800 dark:bg-gray-700 dark:text-gray-300">
|
||||||
|
{props.nonAtomizedTarget}
|
||||||
|
</code>
|
||||||
|
when running without Nx Agents.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
{!props.connectedToCloud && (
|
||||||
|
<div className="flex py-2">
|
||||||
|
<p className="pr-4 normal-case">
|
||||||
|
{props.nxConnectCallback ? (
|
||||||
|
<button
|
||||||
|
className="inline-flex cursor-pointer items-center gap-2 rounded-md px-2 py-1 text-base text-slate-600 ring-2 ring-inset ring-slate-400/40 hover:bg-slate-50 dark:text-slate-300 dark:ring-slate-400/30 dark:hover:bg-slate-800/60"
|
||||||
|
onClick={() => props.nxConnectCallback!()}
|
||||||
|
>
|
||||||
|
<NxCloudIcon className="h-5 w-5 "></NxCloudIcon>
|
||||||
|
<span>Connect to Nx Cloud</span>
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<span className="font-mono">
|
||||||
|
{'Run'}
|
||||||
|
<code className="mx-2 inline rounded bg-gray-100 px-1 font-mono text-gray-800 dark:bg-gray-700 dark:text-gray-300">
|
||||||
|
nx connect
|
||||||
|
</code>
|
||||||
|
{'to connect to Nx Cloud'}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Link({ href, text }: { href: string; text: string }) {
|
||||||
|
return (
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
className="inline text-slate-500 underline decoration-slate-700/50 decoration-dotted decoration-2 dark:text-slate-400 dark:decoration-slate-400/50"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</a>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -99,7 +99,7 @@ export function PropertyInfoTooltip({ type }: PropertyInfoTooltipProps) {
|
|||||||
: ''
|
: ''
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<p className="flex grow items-center gap-2 whitespace-pre-wrap">
|
<p className="flex grow items-center gap-2 whitespace-pre-wrap normal-case">
|
||||||
{propertyInfo.description}
|
{propertyInfo.description}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -25,6 +25,7 @@ import {
|
|||||||
useRole,
|
useRole,
|
||||||
safePolygon,
|
safePolygon,
|
||||||
useTransitionStyles,
|
useTransitionStyles,
|
||||||
|
FloatingPortal,
|
||||||
} from '@floating-ui/react';
|
} from '@floating-ui/react';
|
||||||
|
|
||||||
export type TooltipProps = HTMLAttributes<HTMLDivElement> & {
|
export type TooltipProps = HTMLAttributes<HTMLDivElement> & {
|
||||||
@ -37,6 +38,7 @@ export type TooltipProps = HTMLAttributes<HTMLDivElement> & {
|
|||||||
buffer?: number;
|
buffer?: number;
|
||||||
showTooltipArrow?: boolean;
|
showTooltipArrow?: boolean;
|
||||||
strategy?: 'absolute' | 'fixed';
|
strategy?: 'absolute' | 'fixed';
|
||||||
|
usePortal?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function Tooltip({
|
export function Tooltip({
|
||||||
@ -49,6 +51,7 @@ export function Tooltip({
|
|||||||
strategy = 'absolute',
|
strategy = 'absolute',
|
||||||
buffer = 0,
|
buffer = 0,
|
||||||
showTooltipArrow = true,
|
showTooltipArrow = true,
|
||||||
|
usePortal = false,
|
||||||
}: TooltipProps) {
|
}: TooltipProps) {
|
||||||
const [isOpen, setIsOpen] = useState(open);
|
const [isOpen, setIsOpen] = useState(open);
|
||||||
const arrowRef = useRef(null);
|
const arrowRef = useRef(null);
|
||||||
@ -123,41 +126,49 @@ export function Tooltip({
|
|||||||
...getReferenceProps(),
|
...getReferenceProps(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const renderTooltip = () => (
|
||||||
|
<div
|
||||||
|
ref={refs.setFloating}
|
||||||
|
style={{
|
||||||
|
position: appliedStrategy,
|
||||||
|
top: showTooltipArrow ? y : y + 8 ?? 0,
|
||||||
|
left: x ?? 0,
|
||||||
|
width: 'max-content',
|
||||||
|
...animationStyles,
|
||||||
|
}}
|
||||||
|
className="z-20 min-w-[250px] max-w-prose rounded-md border border-slate-500"
|
||||||
|
{...getFloatingProps()}
|
||||||
|
>
|
||||||
|
{showTooltipArrow && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
left: arrowX != null ? `${arrowX}px` : '',
|
||||||
|
top: arrowY != null ? `${arrowY}px` : '',
|
||||||
|
right: '',
|
||||||
|
bottom: '',
|
||||||
|
[staticSide]: '-4px',
|
||||||
|
}}
|
||||||
|
className="absolute -z-10 h-4 w-4 rotate-45 bg-slate-500"
|
||||||
|
ref={arrowRef}
|
||||||
|
></div>
|
||||||
|
)}
|
||||||
|
<div className="select-text rounded-md bg-white p-3 dark:bg-slate-900 dark:text-slate-400">
|
||||||
|
{content}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!externalReference && !!children
|
{!externalReference && !!children
|
||||||
? cloneElement(children, cloneProps)
|
? cloneElement(children, cloneProps)
|
||||||
: children}
|
: children}
|
||||||
{isOpen && isMounted ? (
|
{isOpen && isMounted ? (
|
||||||
<div
|
usePortal ? (
|
||||||
ref={refs.setFloating}
|
<FloatingPortal>{renderTooltip()}</FloatingPortal>
|
||||||
style={{
|
) : (
|
||||||
position: appliedStrategy,
|
renderTooltip()
|
||||||
top: showTooltipArrow ? y : y + 8 ?? 0,
|
)
|
||||||
left: x ?? 0,
|
|
||||||
width: 'max-content',
|
|
||||||
...animationStyles,
|
|
||||||
}}
|
|
||||||
className="z-10 min-w-[250px] max-w-prose rounded-md border border-slate-500"
|
|
||||||
{...getFloatingProps()}
|
|
||||||
>
|
|
||||||
{showTooltipArrow && (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
left: arrowX != null ? `${arrowX}px` : '',
|
|
||||||
top: arrowY != null ? `${arrowY}px` : '',
|
|
||||||
right: '',
|
|
||||||
bottom: '',
|
|
||||||
[staticSide]: '-4px',
|
|
||||||
}}
|
|
||||||
className="absolute -z-10 h-4 w-4 rotate-45 bg-slate-500"
|
|
||||||
ref={arrowRef}
|
|
||||||
></div>
|
|
||||||
)}
|
|
||||||
<div className="select-text rounded-md bg-white p-3 dark:bg-slate-900 dark:text-slate-400">
|
|
||||||
{content}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : null}
|
) : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -306,6 +306,7 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Runs Cypress Tests in CI",
|
"description": "Runs Cypress Tests in CI",
|
||||||
|
"nonAtomizedTarget": "e2e",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"cypress",
|
"cypress",
|
||||||
],
|
],
|
||||||
@ -329,6 +330,7 @@ describe('@nx/cypress/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Runs Cypress Tests in src/test.cy.ts in CI",
|
"description": "Runs Cypress Tests in src/test.cy.ts in CI",
|
||||||
|
"nonAtomizedTarget": "e2e",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"cypress",
|
"cypress",
|
||||||
],
|
],
|
||||||
|
|||||||
@ -270,6 +270,7 @@ async function buildCypressTargets(
|
|||||||
metadata: {
|
metadata: {
|
||||||
technologies: ['cypress'],
|
technologies: ['cypress'],
|
||||||
description: `Runs Cypress Tests in ${relativeSpecFilePath} in CI`,
|
description: `Runs Cypress Tests in ${relativeSpecFilePath} in CI`,
|
||||||
|
nonAtomizedTarget: options.targetName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
dependsOn.push({
|
dependsOn.push({
|
||||||
@ -288,6 +289,7 @@ async function buildCypressTargets(
|
|||||||
metadata: {
|
metadata: {
|
||||||
technologies: ['cypress'],
|
technologies: ['cypress'],
|
||||||
description: 'Runs Cypress Tests in CI',
|
description: 'Runs Cypress Tests in CI',
|
||||||
|
nonAtomizedTarget: options.targetName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ciTargetGroup.push(options.ciTargetName);
|
ciTargetGroup.push(options.ciTargetName);
|
||||||
|
|||||||
@ -179,6 +179,7 @@ describe('@nx/jest/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Run Jest Tests in CI",
|
"description": "Run Jest Tests in CI",
|
||||||
|
"nonAtomizedTarget": "test",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"jest",
|
"jest",
|
||||||
],
|
],
|
||||||
@ -201,6 +202,7 @@ describe('@nx/jest/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Run Jest Tests in src/unit.spec.ts",
|
"description": "Run Jest Tests in src/unit.spec.ts",
|
||||||
|
"nonAtomizedTarget": "test",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"jest",
|
"jest",
|
||||||
],
|
],
|
||||||
@ -304,48 +306,48 @@ describe('@nx/jest/plugin', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(results).toMatchInlineSnapshot(`
|
expect(results).toMatchInlineSnapshot(`
|
||||||
[
|
[
|
||||||
[
|
[
|
||||||
"proj/jest.config.js",
|
"proj/jest.config.js",
|
||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
"proj": {
|
"proj": {
|
||||||
"metadata": undefined,
|
"metadata": undefined,
|
||||||
"root": "proj",
|
"root": "proj",
|
||||||
"targets": {
|
"targets": {
|
||||||
"test": {
|
"test": {
|
||||||
"cache": true,
|
"cache": true,
|
||||||
"command": "jest",
|
"command": "jest",
|
||||||
"inputs": [
|
"inputs": [
|
||||||
"default",
|
"default",
|
||||||
"^production",
|
"^production",
|
||||||
{
|
{
|
||||||
"externalDependencies": [
|
"externalDependencies": [
|
||||||
"jest",
|
"jest",
|
||||||
"some-package",
|
"some-package",
|
||||||
],
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"description": "Run Jest Tests",
|
||||||
|
"technologies": [
|
||||||
|
"jest",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"cwd": "proj",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{workspaceRoot}/coverage",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"description": "Run Jest Tests",
|
|
||||||
"technologies": [
|
|
||||||
"jest",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
"options": {
|
|
||||||
"cwd": "proj",
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
"{workspaceRoot}/coverage",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
},
|
]
|
||||||
},
|
`);
|
||||||
},
|
|
||||||
],
|
|
||||||
]
|
|
||||||
`);
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -237,6 +237,7 @@ async function buildJestTargets(
|
|||||||
metadata: {
|
metadata: {
|
||||||
technologies: ['jest'],
|
technologies: ['jest'],
|
||||||
description: 'Run Jest Tests in CI',
|
description: 'Run Jest Tests in CI',
|
||||||
|
nonAtomizedTarget: options.targetName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
targetGroup.push(options.ciTargetName);
|
targetGroup.push(options.ciTargetName);
|
||||||
@ -258,6 +259,7 @@ async function buildJestTargets(
|
|||||||
metadata: {
|
metadata: {
|
||||||
technologies: ['jest'],
|
technologies: ['jest'],
|
||||||
description: `Run Jest Tests in ${relativePath}`,
|
description: `Run Jest Tests in ${relativePath}`,
|
||||||
|
nonAtomizedTarget: options.targetName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
targetGroup.push(targetName);
|
targetGroup.push(targetName);
|
||||||
|
|||||||
@ -56,6 +56,7 @@ import { createTaskHasher } from '../../hasher/create-task-hasher';
|
|||||||
|
|
||||||
import { filterUsingGlobPatterns } from '../../hasher/task-hasher';
|
import { filterUsingGlobPatterns } from '../../hasher/task-hasher';
|
||||||
import { ProjectGraphError } from '../../project-graph/error-types';
|
import { ProjectGraphError } from '../../project-graph/error-types';
|
||||||
|
import { isNxCloudUsed } from '../../utils/nx-cloud-utils';
|
||||||
|
|
||||||
export interface GraphError {
|
export interface GraphError {
|
||||||
message: string;
|
message: string;
|
||||||
@ -78,6 +79,7 @@ export interface ProjectGraphClientResponse {
|
|||||||
exclude: string[];
|
exclude: string[];
|
||||||
isPartial: boolean;
|
isPartial: boolean;
|
||||||
errors?: GraphError[];
|
errors?: GraphError[];
|
||||||
|
connectedToCloud?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskGraphClientResponse {
|
export interface TaskGraphClientResponse {
|
||||||
@ -748,11 +750,14 @@ async function createProjectGraphAndSourceMapClientResponse(
|
|||||||
let sourceMaps: ConfigurationSourceMaps;
|
let sourceMaps: ConfigurationSourceMaps;
|
||||||
let isPartial = false;
|
let isPartial = false;
|
||||||
let errors: GraphError[] | undefined;
|
let errors: GraphError[] | undefined;
|
||||||
|
let connectedToCloud: boolean | undefined;
|
||||||
try {
|
try {
|
||||||
const projectGraphAndSourceMaps =
|
const projectGraphAndSourceMaps =
|
||||||
await createProjectGraphAndSourceMapsAsync({ exitOnError: false });
|
await createProjectGraphAndSourceMapsAsync({ exitOnError: false });
|
||||||
projectGraph = projectGraphAndSourceMaps.projectGraph;
|
projectGraph = projectGraphAndSourceMaps.projectGraph;
|
||||||
sourceMaps = projectGraphAndSourceMaps.sourceMaps;
|
sourceMaps = projectGraphAndSourceMaps.sourceMaps;
|
||||||
|
|
||||||
|
connectedToCloud = isNxCloudUsed(readNxJson());
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof ProjectGraphError) {
|
if (e instanceof ProjectGraphError) {
|
||||||
projectGraph = e.getPartialProjectGraph();
|
projectGraph = e.getPartialProjectGraph();
|
||||||
@ -786,7 +791,14 @@ async function createProjectGraphAndSourceMapClientResponse(
|
|||||||
|
|
||||||
const hasher = createHash('sha256');
|
const hasher = createHash('sha256');
|
||||||
hasher.update(
|
hasher.update(
|
||||||
JSON.stringify({ layout, projects, dependencies, sourceMaps, errors })
|
JSON.stringify({
|
||||||
|
layout,
|
||||||
|
projects,
|
||||||
|
dependencies,
|
||||||
|
sourceMaps,
|
||||||
|
errors,
|
||||||
|
connectedToCloud,
|
||||||
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
const hash = hasher.digest('hex');
|
const hash = hasher.digest('hex');
|
||||||
@ -816,6 +828,7 @@ async function createProjectGraphAndSourceMapClientResponse(
|
|||||||
fileMap,
|
fileMap,
|
||||||
isPartial,
|
isPartial,
|
||||||
errors,
|
errors,
|
||||||
|
connectedToCloud,
|
||||||
},
|
},
|
||||||
sourceMapResponse: sourceMaps,
|
sourceMapResponse: sourceMaps,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -128,6 +128,7 @@ export interface TargetMetadata {
|
|||||||
[k: string]: any;
|
[k: string]: any;
|
||||||
description?: string;
|
description?: string;
|
||||||
technologies?: string[];
|
technologies?: string[];
|
||||||
|
nonAtomizedTarget?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TargetDependencyConfig {
|
export interface TargetDependencyConfig {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { NxJsonConfiguration, readNxJson } from '../config/nx-json';
|
import { NxJsonConfiguration, readNxJson } from '../config/nx-json';
|
||||||
|
|
||||||
export function isNxCloudUsed(nxJson: NxJsonConfiguration) {
|
export function isNxCloudUsed(nxJson: NxJsonConfiguration): boolean {
|
||||||
return (
|
return (
|
||||||
process.env.NX_CLOUD_ACCESS_TOKEN ||
|
!!process.env.NX_CLOUD_ACCESS_TOKEN ||
|
||||||
!!nxJson.nxCloudAccessToken ||
|
!!nxJson.nxCloudAccessToken ||
|
||||||
!!Object.values(nxJson.tasksRunnerOptions ?? {}).find(
|
!!Object.values(nxJson.tasksRunnerOptions ?? {}).find(
|
||||||
(r) => r.runner == '@nrwl/nx-cloud' || r.runner == 'nx-cloud'
|
(r) => r.runner == '@nrwl/nx-cloud' || r.runner == 'nx-cloud'
|
||||||
|
|||||||
@ -99,6 +99,7 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Runs Playwright Tests in CI",
|
"description": "Runs Playwright Tests in CI",
|
||||||
|
"nonAtomizedTarget": "e2e",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"playwright",
|
"playwright",
|
||||||
],
|
],
|
||||||
@ -191,6 +192,7 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Runs Playwright Tests in CI",
|
"description": "Runs Playwright Tests in CI",
|
||||||
|
"nonAtomizedTarget": "e2e",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"playwright",
|
"playwright",
|
||||||
],
|
],
|
||||||
@ -273,6 +275,7 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Runs Playwright Tests in CI",
|
"description": "Runs Playwright Tests in CI",
|
||||||
|
"nonAtomizedTarget": "e2e",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"playwright",
|
"playwright",
|
||||||
],
|
],
|
||||||
@ -297,6 +300,7 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Runs Playwright Tests in tests/run-me.spec.ts in CI",
|
"description": "Runs Playwright Tests in tests/run-me.spec.ts in CI",
|
||||||
|
"nonAtomizedTarget": "e2e",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"playwright",
|
"playwright",
|
||||||
],
|
],
|
||||||
@ -324,6 +328,7 @@ describe('@nx/playwright/plugin', () => {
|
|||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "Runs Playwright Tests in tests/run-me-2.spec.ts in CI",
|
"description": "Runs Playwright Tests in tests/run-me-2.spec.ts in CI",
|
||||||
|
"nonAtomizedTarget": "e2e",
|
||||||
"technologies": [
|
"technologies": [
|
||||||
"playwright",
|
"playwright",
|
||||||
],
|
],
|
||||||
|
|||||||
@ -215,6 +215,7 @@ async function buildPlaywrightTargets(
|
|||||||
metadata: {
|
metadata: {
|
||||||
technologies: ['playwright'],
|
technologies: ['playwright'],
|
||||||
description: `Runs Playwright Tests in ${relativeSpecFilePath} in CI`,
|
description: `Runs Playwright Tests in ${relativeSpecFilePath} in CI`,
|
||||||
|
nonAtomizedTarget: options.targetName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
dependsOn.push({
|
dependsOn.push({
|
||||||
@ -241,6 +242,7 @@ async function buildPlaywrightTargets(
|
|||||||
metadata: {
|
metadata: {
|
||||||
technologies: ['playwright'],
|
technologies: ['playwright'],
|
||||||
description: 'Runs Playwright Tests in CI',
|
description: 'Runs Playwright Tests in CI',
|
||||||
|
nonAtomizedTarget: options.targetName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
ciTargetGroup.push(options.ciTargetName);
|
ciTargetGroup.push(options.ciTargetName);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user