nx/nx-dev/ui-cloud/src/lib/understand-workspace.tsx

834 lines
32 KiB
TypeScript

'use client';
import {
ArrowLongRightIcon,
ArrowsRightLeftIcon,
ChevronRightIcon,
ClipboardDocumentIcon,
DocumentIcon,
InboxArrowDownIcon,
LockClosedIcon,
SparklesIcon,
} from '@heroicons/react/24/outline';
import { SectionHeading } from '@nx/nx-dev/ui-common';
import { BentoGrid, BentoGridItem } from './elements/bento-grid';
import { cx } from '@nx/nx-dev/ui-primitives';
import { animate, motion, useMotionValue, useTransform } from 'framer-motion';
import { ReactElement, useEffect } from 'react';
import { usePrefersReducedMotion } from '@nx/nx-dev/ui-animations';
export function UnderstandWorkspace(): ReactElement {
return (
<section id="deep-understanding" className="scroll-mt-24">
<div className="mx-auto max-w-7xl px-6 lg:px-8">
<div className="mx-auto max-w-2xl text-center">
<SectionHeading as="h2" variant="title">
Deep understanding of your workspace
</SectionHeading>
<SectionHeading as="p" variant="subtitle" className="mt-6">
Nx Cloud knows your build tools, how your projects relate to each
other, and what every task does.
</SectionHeading>
</div>
{/*FEATURES CONTAINER*/}
<BentoGrid className="mx-auto mt-20 w-full md:auto-rows-[22rem]">
{items.map((item, i) => (
<BentoGridItem
key={i}
title={item.title}
description={item.description}
header={item.header}
className={cx('[&>p:text-lg]', item.className)}
icon={item.icon}
/>
))}
</BentoGrid>
</div>
</section>
);
}
const Caching = () => {
const variants = {
hidden: {
opacity: 0,
transition: {
when: 'afterChildren',
},
},
visible: {
opacity: 1,
},
};
const items = [
{
cache: 'remote',
target: 'build',
project: 'website',
},
{
cache: 'remote',
target: 'test',
project: 'express',
},
{
cache: 'remote',
target: 'build',
project: 'eslint',
},
{
cache: 'remote',
target: 'lint',
project: 'autoloan',
},
{
cache: 'remote',
target: 'test',
project: 'website',
},
{
cache: 'remote',
target: 'lint',
project: 'website',
},
{
cache: 'remote',
target: 'build-base',
project: 'express',
},
{
cache: 'remote',
target: 'build',
project: 'express',
},
{
cache: 'remote',
target: 'lint',
project: 'express',
},
{
cache: 'remote',
target: 'test',
project: 'autoloan',
},
];
return (
<motion.div
initial="hidden"
variants={variants}
whileInView="visible"
viewport={{ once: true }}
className="flex h-full min-h-[12rem] w-full flex-1 flex-col gap-2"
>
<motion.div className="flex items-center gap-1.5 text-center text-sm italic">
<SparklesIcon aria-hidden="true" className="h-4 w-4" />
<span className="font-semibold">
<Counter value={items.length + 123} duration={5} />
</span>
tasks replayed instantly with cache
</motion.div>
<div className="flex flex-1 flex-col divide-y divide-neutral-100 overflow-auto rounded-lg border border-neutral-100 dark:divide-slate-700 dark:border-slate-700 dark:bg-slate-950">
{items.map((i, idx) => (
<div
key={`project-${i}-${idx}`}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="m-1 h-2.5 w-2.5 flex-none rounded-full bg-emerald-500" />
<div className="flex min-w-[4rem]">
<span className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
{i.cache}
</span>
</div>
<div
className="grow truncate text-left text-sm font-medium"
data-testid="task-target"
>
{i.target}
</div>
<span className="inline-flex cursor-default items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20 dark:bg-green-500/10 dark:text-green-400 dark:ring-green-500/20">
{i.project}
</span>
<div className="text-xs">&lt; 1s</div>
</div>
))}
</div>
</motion.div>
);
};
const FlakyTasks = () => {
const shouldReduceMotion = usePrefersReducedMotion();
const variants = {
hidden: {
opacity: 0,
transition: {
when: 'afterChildren',
},
},
visible: {
opacity: 1,
},
};
const itemVariants = {
visible: (i: number) => ({
opacity: 1,
x: 0,
transition: {
delay: shouldReduceMotion ? 0 : i * 0.2,
duration: shouldReduceMotion ? 0 : 0.275,
ease: 'easeOut',
when: 'beforeChildren',
staggerChildren: 0.3,
},
}),
hidden: {
opacity: 0,
x: -100,
transition: {
when: 'afterChildren',
},
},
};
return (
<motion.div
initial="hidden"
variants={variants}
whileInView="visible"
viewport={{ once: true }}
className="flex h-full min-h-[12rem] w-full flex-1 flex-col gap-2"
>
<motion.div className="flex items-center gap-1.5 text-center text-sm">
Running
<ChevronRightIcon aria-hidden="true" className="h-3 w-3" />
<code className="text-xs font-medium">
nx affected --targets=e2e,test
</code>
</motion.div>
<div className="flex flex-1 flex-col divide-y divide-neutral-100 overflow-auto rounded-lg border border-neutral-100 dark:divide-slate-700 dark:border-slate-700 dark:bg-slate-950">
<motion.div
custom={1}
variants={itemVariants}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="m-1 h-2.5 w-2.5 flex-none rounded-full bg-emerald-500" />
<div className="flex min-w-[5rem]">
<span className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
miss
</span>
</div>
<div className="grow truncate text-left text-sm font-medium">
test
</div>
<motion.span
custom={3}
variants={itemVariants}
className="inline-flex cursor-default items-center rounded-md bg-yellow-400/10 px-2 py-1 text-xs font-medium text-yellow-500 ring-1 ring-inset ring-yellow-400/20 dark:bg-yellow-400/10 dark:text-yellow-500 dark:ring-yellow-400/20"
>
flaky
</motion.span>
<motion.span
custom={2}
variants={itemVariants}
className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20"
>
1 retry
</motion.span>
<span className="inline-flex cursor-default items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20 dark:bg-green-500/10 dark:text-green-400 dark:ring-green-500/20">
website
</span>
</motion.div>
<motion.div
custom={2}
variants={itemVariants}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="flex items-center gap-2">
<div className="m-1 h-2.5 w-2.5 flex-none rounded-full bg-red-500"></div>
<div className="flex min-w-[5rem]">
<span className="whitespace-nowrap text-sm font-medium">
Failed
</span>
</div>
</div>
<div className="grow truncate text-left text-sm font-medium">e2e</div>
<span className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
1 retry
</span>
<span className="inline-flex items-center rounded-md bg-red-50 px-2 py-1 text-xs font-medium text-red-700 ring-1 ring-inset ring-red-600/10 dark:bg-red-400/10 dark:text-red-400 dark:ring-red-400/20">
website
</span>
</motion.div>
<motion.div
custom={3}
variants={itemVariants}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="flex items-center gap-2">
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</div>
<div className="flex min-w-[5rem]">
<span className="whitespace-nowrap text-sm font-medium">
In progress
</span>
</div>
</div>
<div className="grow truncate text-left text-sm font-medium">
test
</div>
<motion.span
custom={15}
variants={itemVariants}
className="inline-flex cursor-default items-center rounded-md bg-yellow-400/10 px-2 py-1 text-xs font-medium text-yellow-500 ring-1 ring-inset ring-yellow-400/20"
>
flaky
</motion.span>
<motion.span
custom={10}
variants={itemVariants}
className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20"
>
1 retry
</motion.span>
<span className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
ui-cdk
</span>
</motion.div>
<motion.div
custom={4}
variants={itemVariants}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="m-1 h-2.5 w-2.5 flex-none rounded-full bg-emerald-500" />
<div className="flex min-w-[5rem]">
<span className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
remote
</span>
</div>
<div className="grow truncate text-left text-sm font-medium">
lint
</div>
<span className="inline-flex cursor-default items-center rounded-md bg-green-50 px-2 py-1 text-xs font-medium text-green-700 ring-1 ring-inset ring-green-600/20 dark:bg-green-500/10 dark:text-green-400 dark:ring-green-500/20">
website
</span>
</motion.div>
<motion.div
custom={5}
variants={itemVariants}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="flex items-center gap-2">
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</div>
<div className="flex min-w-[5rem]">
<span className="whitespace-nowrap text-sm font-medium">
In progress
</span>
</div>
</div>
<div className="grow truncate text-left text-sm font-medium">
build
</div>
<span className="inline-flex cursor-default items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
ui-cdk
</span>
</motion.div>
</div>
</motion.div>
);
};
const SplitE2eTests = () => {
const variants = {
hidden: {
opacity: 0,
transition: {
when: 'afterChildren',
},
},
visible: {
opacity: 1,
},
};
const uiDialogsTests = [
'e2e/libs/ui-cdk/spec-1.tsx',
'e2e/libs/ui-cdk/spec-2.tsx',
];
const websiteTests = [
'e2e/apps/website/spec-1.tsx',
'e2e/apps/website/spec-2.tsx',
'e2e/apps/website/spec-3.tsx',
'e2e/apps/website/spec-4.tsx',
'e2e/apps/website/spec-5.tsx',
'e2e/apps/website/spec-6.tsx',
];
return (
<motion.div
initial="hidden"
variants={variants}
whileInView="visible"
viewport={{ once: true }}
className="flex h-full min-h-[12rem] w-full flex-1 flex-col gap-2"
>
<motion.div className="flex items-center gap-1.5 text-center text-sm">
Running
<ChevronRightIcon aria-hidden="true" className="h-3 w-3" />
<code className="text-xs font-medium">nx affected --targets=e2e</code>
</motion.div>
<div className="flex flex-1 flex-col divide-y divide-neutral-100 overflow-auto rounded-lg border border-neutral-100 bg-white dark:divide-slate-700 dark:border-slate-700 dark:bg-slate-950">
<div className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40">
<div className="flex items-center gap-2">
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</div>
<div className="flex min-w-[5rem]">
<span className="whitespace-nowrap text-sm font-medium">
In progress
</span>
</div>
</div>
<div className="grow truncate text-left text-sm font-medium">e2e</div>
<span className="inline-flex items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
ui-cdk
</span>
</div>
{uiDialogsTests.map((i, idx) => (
<div
key={`${i}-${idx}`}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="w-4" />
<ArrowLongRightIcon aria-hidden="true" className="h-4 w-4" />
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</div>
<div className="grow truncate text-left text-sm">{i}</div>
</div>
))}
<div className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40">
<div className="flex items-center gap-2">
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</div>
<div className="flex min-w-[5rem]">
<span className="whitespace-nowrap text-sm font-medium">
In progress
</span>
</div>
</div>
<div className="grow truncate text-left text-sm font-medium">e2e</div>
<span className="inline-flex items-center rounded-md bg-slate-50 px-2 py-1 text-xs font-medium text-gray-600 ring-1 ring-inset ring-gray-500/10 dark:bg-gray-400/10 dark:text-gray-400 dark:ring-gray-400/20">
website
</span>
</div>
{websiteTests.map((i, idx) => (
<div
key={`${i}-${idx}`}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-900/40"
>
<div className="w-4" />
<ArrowLongRightIcon aria-hidden="true" className="h-4 w-4" />
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500" />
</div>
<div className="grow truncate text-left text-sm">{i}</div>
</div>
))}
</div>
</motion.div>
);
};
const TaskDistribution = () => {
const shouldReduceMotion = usePrefersReducedMotion();
const variants = {
hidden: {
opacity: 0,
transition: {
when: 'afterChildren',
},
},
visible: {
opacity: 1,
},
};
const itemVariants = {
visible: (i: number) => ({
opacity: 1,
x: 0,
transition: {
delay: shouldReduceMotion ? 0 : i * 0.2,
duration: shouldReduceMotion ? 0 : 0.275,
ease: 'easeOut',
when: 'beforeChildren',
staggerChildren: 0.3,
},
}),
hidden: {
opacity: 0,
x: -100,
transition: {
when: 'afterChildren',
},
},
};
const agent1Items = ['website:build-base', 'website:build'];
const agent2Items = ['docs:lint', 'express:test', 'website:lint'];
const agent3Items = ['graph-client:build', 'plugin:test'];
const nxReplayItems = [
'graph-client:lint',
'plugin:lint',
'website:test',
'vite:test',
'vite:build',
];
const notStartedTasks = ['js:build', 'js:lint'];
return (
<motion.div
initial="hidden"
variants={variants}
whileInView="visible"
viewport={{ once: true }}
className="relative flex h-full min-h-[12rem] w-full flex-1 flex-col gap-2"
>
<div className="grid max-h-full grid-cols-2 items-stretch gap-8 overflow-hidden p-1 lg:grid-cols-3">
<motion.div
custom={2}
variants={itemVariants}
className="relative overflow-x-hidden rounded-lg bg-white p-2 ring-1 ring-neutral-100 dark:bg-slate-950 dark:ring-slate-700"
>
<p className="text-sm font-medium text-slate-700 dark:text-slate-400">
Main Workflow
</p>
<div className="mt-2 flex flex-col gap-1">
<p className="overflow-x-auto truncate py-2 font-mono text-xs font-medium text-slate-900 dark:text-slate-400">
nx affected --target=build,lint,test
</p>
<div className="flex h-1.5 w-full flex-row rounded-full">
<div
title="2 tasks in completed"
className="cursor-pointer rounded-l-full bg-green-400 dark:bg-green-600"
style={{ flexGrow: 8 }}
/>
<div
title="12 tasks in progress"
className="cursor-pointer bg-yellow-400 dark:bg-yellow-600"
style={{ flexGrow: 12 }}
/>
<div
title="24 tasks not started"
className="cursor-pointer rounded-r-full bg-slate-100 dark:bg-slate-600"
style={{ flexGrow: 24 }}
/>
</div>
<div className="mt-2 flex flex-1 flex-col divide-y divide-neutral-100 overflow-auto rounded-lg border border-neutral-100 dark:divide-slate-700 dark:border-slate-700">
{notStartedTasks.map((i, idx) => (
<motion.div
key={`${i}-${idx}`}
custom={idx + 3}
variants={itemVariants}
className="flex w-full flex-row items-center gap-2 p-2 transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-800/40"
>
<div className="text-xs">{i}</div>
</motion.div>
))}
</div>
</div>
</motion.div>
<motion.div
custom={3}
variants={itemVariants}
className="relative flex flex-col gap-2 overflow-x-hidden rounded-lg bg-white p-2 ring-1 ring-neutral-100 dark:bg-slate-950 dark:ring-slate-700"
>
<p className="text-sm font-medium text-slate-700 dark:text-slate-400">
Nx Agents
</p>
<div className="flex flex-1 flex-col overflow-auto">
<motion.div custom={4} variants={itemVariants} className="relative">
<div className="sticky top-0 z-10 mt-1 rounded-md border border-neutral-100 bg-slate-50 p-2 transition hover:bg-slate-100 dark:border-slate-800 dark:bg-slate-900 dark:hover:bg-slate-800">
<div className="flex items-center gap-x-2 text-xs font-medium">
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500"></div>
</div>
Agent 1<span className="flex-grow"></span>
<span className="mr-1 opacity-80">{agent1Items.length}</span>
</div>
</div>
<ul className="my-2 overflow-y-auto overflow-x-hidden">
{agent1Items.map((i, idx) => (
<motion.li
key={`agent-${i}-${idx}`}
custom={idx + 5}
variants={itemVariants}
className="truncate p-1 pl-4 text-xs"
>
{i}
</motion.li>
))}
</ul>
</motion.div>
<motion.div custom={6} variants={itemVariants} className="relative">
<div className="sticky top-0 z-10 mt-1 rounded-md border border-neutral-100 bg-slate-50 p-2 transition hover:bg-slate-100 dark:border-slate-800 dark:bg-slate-900 dark:hover:bg-slate-800">
<div className="flex items-center gap-x-2 text-xs font-medium">
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500"></div>
</div>
Agent 2<span className="flex-grow"></span>
<span className="mr-1 opacity-80">{agent2Items.length}</span>
</div>
</div>
<ul className="my-2 overflow-y-auto overflow-x-hidden">
{agent2Items.map((i, idx) => (
<motion.li
key={`agent-${i}-${idx}`}
custom={idx + 7}
variants={itemVariants}
className="truncate p-1 pl-4 text-xs"
>
{i}
</motion.li>
))}
</ul>
</motion.div>
<motion.div
custom={8}
variants={itemVariants}
className="relative hidden lg:block"
>
<div className="sticky top-0 z-10 mt-1 rounded-md border border-neutral-100 bg-slate-50 p-2 transition hover:bg-slate-100 dark:border-slate-800 dark:bg-slate-900 dark:hover:bg-slate-800">
<div className="flex items-center gap-x-2 text-xs font-medium">
<div className="flex-none animate-pulse rounded-full bg-yellow-500/20 p-1">
<div className="h-2 w-2 rounded-full bg-yellow-500"></div>
</div>
Agent 3<span className="flex-grow"></span>
<span className="mr-1 opacity-80">{agent3Items.length}</span>
</div>
</div>
<ul className="my-2 overflow-y-auto overflow-x-hidden">
{agent3Items.map((i, idx) => (
<motion.li
key={`agent-${i}-${idx}`}
custom={idx + 9}
variants={itemVariants}
className="truncate p-1 pl-4 text-xs"
>
{i}
</motion.li>
))}
</ul>
</motion.div>
</div>
</motion.div>
<motion.div
custom={4}
variants={itemVariants}
className="relative hidden flex-col gap-2 overflow-x-hidden rounded-lg bg-white p-2 ring-1 ring-neutral-100 lg:flex dark:bg-slate-950 dark:ring-slate-700"
>
<p className="text-sm font-medium text-slate-700 dark:text-slate-400">
Nx Replay
</p>
<div className="flex flex-1 flex-col divide-y divide-neutral-100 overflow-auto rounded-lg border border-neutral-100 dark:divide-slate-800 dark:border-slate-800">
{nxReplayItems.map((i, idx) => (
<motion.div
key={`replay-${i}-${idx}`}
custom={idx + 10}
variants={itemVariants}
className="flex w-full flex-row items-center gap-2 p-2 text-xs transition-colors ease-out hover:bg-slate-50/40 dark:hover:bg-slate-800/40"
>
{i}
</motion.div>
))}
</div>
</motion.div>
</div>
</motion.div>
);
};
const ActionableErrorFeedback = () => {
const variants = {
hidden: {
opacity: 0,
transition: {
when: 'afterChildren',
},
},
visible: {
opacity: 1,
},
};
return (
<motion.div
initial="hidden"
variants={variants}
whileInView="visible"
viewport={{ once: true }}
className="flex h-full min-h-[12rem] w-full flex-1 flex-col gap-1"
>
<div className="flex items-center gap-1.5">
{/*STATUS*/}
<div className="flex items-center gap-2">
<div className="m-1 h-2.5 w-2.5 flex-none rounded-full bg-red-500"></div>
<span
className="whitespace-nowrap text-lg font-medium"
data-testid="status-label"
>
Failed
</span>
with code: 1
</div>
</div>
{/*COMPARE & FLAKY*/}
<div className="flex items-center justify-end gap-1.5">
<button
type="button"
className="cursor-default rounded bg-white px-2 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 dark:bg-white/10 dark:text-slate-400 dark:ring-slate-700"
>
Compare to similar tasks
</button>
<button
type="button"
className="cursor-default rounded bg-white px-2 py-1 text-xs font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 dark:bg-white/10 dark:text-slate-400 dark:ring-slate-700"
>
Set as "not flaky"
</button>
</div>
<div>
<div className="border-b border-neutral-100 dark:border-slate-700">
<div className="-mb-px flex space-x-4">
<span className="cursor-default whitespace-nowrap border-b-2 border-transparent px-0.5 py-2 text-xs font-medium text-gray-500 dark:text-slate-400">
Attempt 1
</span>
<span className="cursor-default whitespace-nowrap border-b-2 border-blue-500 px-0.5 py-2 text-xs font-medium text-blue-500 dark:border-sky-600 dark:text-sky-600">
Attempt 2
</span>
</div>
</div>
</div>
<p className="text-xs">Feb 23, 2024 08:57:49 - 08:57:54 (4s)</p>
<motion.div className="terminal-output flex max-h-full min-h-[2rem] flex-col overflow-visible rounded-lg border border-slate-200 bg-slate-50 font-mono text-xs leading-normal text-slate-800 subpixel-antialiased dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200">
<div className="flex items-center justify-between gap-4 rounded-t-lg border-b border-slate-200 bg-slate-100 px-2 py-1 dark:border-slate-700 dark:bg-slate-800">
<div className="font-sans text-sm font-medium">
<span className="group relative flex cursor-pointer items-center overflow-hidden whitespace-nowrap subpixel-antialiased dark:text-slate-300">
<span>nx run nx-dev:build</span>
<span className="transform opacity-0 transition-all">
<ClipboardDocumentIcon className="h-4 w-4" />
</span>
</span>
</div>
</div>
<div className="overflow-auto">
<pre className="overflow-x-hidden p-1 dark:text-slate-400">
{`nx run nx-dev:sitemap ✨ [next-sitemap]
Loading next-sitemap config:file:///home/workflows/workspace/nx-dev/nx-dev/next-sitemap.config.js
❌ [next-sitemap] Unable to find export-maker.
Make sure to build the project using "next build" command
node:internal/process/promises:289
triggerUncaughtException(err, true /* fromPromise */); ^
[Error:ENOENT: no such file or directory, stat '/home/workflows/workspace/dist/nx-dev/nx-dev/.next/export-marker.json']
errno: -2, code: 'ENOENT', syscall: 'stat', path: '/home/workflows/workspace/dist/nx-dev/nx-dev/.next/export-marker.json'
Node.js v20.9.0 Warning: command "pnpm next-sitemap --config
./nx-dev/nx-dev/next-sitemap.config.js" exited with non-zero status code`}
</pre>
</div>
</motion.div>
</motion.div>
);
};
export function Counter({
value,
duration = 2,
}: {
value: number;
duration?: number;
}) {
const count = useMotionValue(0);
const rounded = useTransform(count, Math.round);
const shouldReduceMotion = usePrefersReducedMotion();
if (shouldReduceMotion) {
duration = 0;
}
useEffect(() => {
const animation = animate(count, value, {
type: 'tween',
ease: 'easeOut',
duration,
});
return animation.stop;
}, []);
return <motion.span>{rounded}</motion.span>;
}
const items = [
{
title: 'Nx Agents: seamless task distribution',
description: (
<>
Nx Cloud manages CI agent machines, offloading complex machine
provisioning from your CI provider. Integration is as simple as
initiating a distributed run on your provider, with Nx Agents handling
the rest - streamlining operations and enhancing cost efficiency.
</>
),
header: <TaskDistribution />,
className: 'md:col-span-2',
icon: <ArrowsRightLeftIcon className="h-4 w-4 text-neutral-500" />,
},
{
title: 'Nx Replay: secure computation cache',
description: (
<>
Nx Cloud caches and restores task results, across PRs and local
machines, drastically accelerating your CI runs.
</>
),
header: <Caching />,
className: 'md:col-span-1',
icon: <LockClosedIcon className="h-4 w-4 text-neutral-500" />,
},
{
title: 'Atomizer: E2E test splitting',
description: (
<>
Nx Cloud splits large e2e projects into fine-grained test runs, enabling
more efficient distribution and dramatically reducing CI times.
</>
),
header: <SplitE2eTests />,
className: 'md:col-span-1',
icon: <ClipboardDocumentIcon className="h-4 w-4 text-neutral-500" />,
},
{
title: 'Flaky task detection',
description: (
<>
Nx Cloud automatically identifies flaky tasks from any tool and
initiates a re-run of those specific tasks, optimizing resource usage
for peak efficiency.
</>
),
header: <FlakyTasks />,
className: 'md:col-span-1',
icon: <DocumentIcon className="h-4 w-4 text-neutral-500" />,
},
{
title: 'Actionable feedback',
description: (
<>
Nx Cloud lets you see what went wrong, and how to fix it. It understands
your command and lets you find the logs you need.
</>
),
header: <ActionableErrorFeedback />,
className: 'md:col-span-1',
icon: <InboxArrowDownIcon className="h-4 w-4 text-neutral-500" />,
},
];