diff --git a/nx-dev/nx-dev/pages/enterprise.tsx b/nx-dev/nx-dev/pages/enterprise.tsx index 84257850cf12f3..e1e56019bc5b90 100644 --- a/nx-dev/nx-dev/pages/enterprise.tsx +++ b/nx-dev/nx-dev/pages/enterprise.tsx @@ -3,29 +3,31 @@ import { NextSeo } from 'next-seo'; import { DefaultLayout } from '@nx/nx-dev/ui-common'; import { CallToAction, - DownloadEbook, - EnterpriseAddons, + CustomerLogos, + CustomerMetrics, Hero, - MetricsAndCustomers, - ScaleYourPeople, + HetznerCloudTestimonial, + MakeYourCiFast, + ScaleOrganizationIntro, + ScaleYourOrganization, Security, - TrustedBy, - SolveYourCi, + TestimonialCarousel, + VmwareTestimonial, } from '@nx/nx-dev/ui-enterprise'; -import { TrialCallout } from '@nx/nx-dev/ui-pricing'; import { requestFreeTrial } from '../lib/components/headerCtaConfigs'; +import { ReactElement } from 'react'; -export function Enterprise(): JSX.Element { +export function Enterprise(): ReactElement { const router = useRouter(); return ( <> - +
+
+
- +
- +
-
- -
-
- +
+ +
-
- +
+
- +
- -
-
- +
-
+
diff --git a/nx-dev/nx-dev/public/images/enterprise/nx-agents.avif b/nx-dev/nx-dev/public/images/enterprise/nx-agents.avif new file mode 100644 index 00000000000000..a7e897ed378301 Binary files /dev/null and b/nx-dev/nx-dev/public/images/enterprise/nx-agents.avif differ diff --git a/nx-dev/nx-dev/public/images/enterprise/nx-atomizer.avif b/nx-dev/nx-dev/public/images/enterprise/nx-atomizer.avif new file mode 100644 index 00000000000000..7f183df74835d1 Binary files /dev/null and b/nx-dev/nx-dev/public/images/enterprise/nx-atomizer.avif differ diff --git a/nx-dev/nx-dev/public/images/enterprise/nx-flaky-tasks-detection.avif b/nx-dev/nx-dev/public/images/enterprise/nx-flaky-tasks-detection.avif new file mode 100644 index 00000000000000..a25ed4446f25d6 Binary files /dev/null and b/nx-dev/nx-dev/public/images/enterprise/nx-flaky-tasks-detection.avif differ diff --git a/nx-dev/nx-dev/public/images/enterprise/nx-partnership.avif b/nx-dev/nx-dev/public/images/enterprise/nx-partnership.avif new file mode 100644 index 00000000000000..6d64a30fb0341d Binary files /dev/null and b/nx-dev/nx-dev/public/images/enterprise/nx-partnership.avif differ diff --git a/nx-dev/nx-dev/public/images/enterprise/nx-replay.avif b/nx-dev/nx-dev/public/images/enterprise/nx-replay.avif new file mode 100644 index 00000000000000..3d5942f33ad785 Binary files /dev/null and b/nx-dev/nx-dev/public/images/enterprise/nx-replay.avif differ diff --git a/nx-dev/nx-dev/public/images/enterprise/video-story-pavlo-grosse.avif b/nx-dev/nx-dev/public/images/enterprise/video-story-pavlo-grosse.avif new file mode 100644 index 00000000000000..f7784c72391f17 Binary files /dev/null and b/nx-dev/nx-dev/public/images/enterprise/video-story-pavlo-grosse.avif differ diff --git a/nx-dev/ui-animations/src/lib/marquee.tsx b/nx-dev/ui-animations/src/lib/marquee.tsx index a5d04159bae45a..e7684967e56c99 100644 --- a/nx-dev/ui-animations/src/lib/marquee.tsx +++ b/nx-dev/ui-animations/src/lib/marquee.tsx @@ -53,13 +53,16 @@ export function Marquee({ .map((_, i) => (
{children}
diff --git a/nx-dev/ui-common/src/lib/default-layout.tsx b/nx-dev/ui-common/src/lib/default-layout.tsx index a27b48018de995..f1d776e3f27d71 100644 --- a/nx-dev/ui-common/src/lib/default-layout.tsx +++ b/nx-dev/ui-common/src/lib/default-layout.tsx @@ -24,7 +24,7 @@ export function DefaultLayout({ aria-hidden="true" >
{/*DESKTOP*/} -
+
{/*PRIMARY NAVIGATION*/}
{/*LOGO*/} diff --git a/nx-dev/ui-enterprise/src/index.ts b/nx-dev/ui-enterprise/src/index.ts index b9a6c7abff577f..cc6ea94fead6ef 100644 --- a/nx-dev/ui-enterprise/src/index.ts +++ b/nx-dev/ui-enterprise/src/index.ts @@ -1,10 +1,11 @@ export * from './lib/call-to-action'; -export * from './lib/download-case-study'; -export * from './lib/download-ebook'; -export * from './lib/enterprise-addons'; export * from './lib/hero'; -export * from './lib/metrics-and-customers'; -export * from './lib/scale-your-people'; export * from './lib/security'; -export * from './lib/trusted-by'; -export * from './lib/solve-your-ci'; +export * from './lib/customer-logos'; +export * from './lib/customer-metrics'; +export * from './lib/make-your-ci-fast'; +export * from './lib/hetzner-cloud-testimonial'; +export * from './lib/vmware-testimonial'; +export * from './lib/scale-your-organization'; +export * from './lib/testimonial-carousel'; +export * from './lib/download-case-study'; diff --git a/nx-dev/ui-enterprise/src/lib/bento-grid.tsx b/nx-dev/ui-enterprise/src/lib/bento-grid.tsx deleted file mode 100644 index b269013c0df6de..00000000000000 --- a/nx-dev/ui-enterprise/src/lib/bento-grid.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import Link from 'next/link'; -import { ReactNode } from 'react'; -import { cx } from '@nx/nx-dev/ui-primitives'; - -export const BentoGrid = ({ - className, - children, -}: { - className?: string; - children?: ReactNode; -}) => { - return ( -
- {children} -
- ); -}; - -export const BentoGridItem = ({ - className, - title = null, - description = null, - header, - url = null, - icon, -}: { - className?: string; - title?: string | ReactNode | null; - description?: string | ReactNode | null; - header: ReactNode; - icon?: ReactNode; - url?: string | null; -}) => { - return ( -
- {header} -
-
-
- {icon} {title} -
- {description && ( -
- {description} -
- )} -
- {url ? ( - - - - - - ) : null} -
-
- ); -}; diff --git a/nx-dev/ui-enterprise/src/lib/call-to-action.tsx b/nx-dev/ui-enterprise/src/lib/call-to-action.tsx index c9a16c3cd4f5a7..a351fb9a67062b 100644 --- a/nx-dev/ui-enterprise/src/lib/call-to-action.tsx +++ b/nx-dev/ui-enterprise/src/lib/call-to-action.tsx @@ -1,11 +1,17 @@ import Link from 'next/link'; +import { ReactElement } from 'react'; +import { sendCustomEvent } from '@nx/nx-dev/feature-analytics'; -export function CallToAction(): JSX.Element { +export function CallToAction(): ReactElement { return ( -
+

- Your organization's transformation -
- starts now + Get your hands dirty and try it out for yourself.

+ sendCustomEvent( + 'request-trial-click', + 'enterprise-bottom-cta', + 'enterprise' + ) + } + className="rounded-md bg-slate-950 px-3.5 py-2.5 text-sm font-semibold text-slate-100 shadow-sm hover:bg-slate-800 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-white dark:bg-white dark:text-slate-900 dark:hover:bg-slate-100" > - Talk to engineering + Request a free trial

- Ready to talk terms?{' '} + Want to talk terms or see a demo?{' '} + sendCustomEvent( + 'contact-team', + 'enterprise-bottom-cta', + 'enterprise' + ) + } > - Speak directly to sales + Reach out to our team .

diff --git a/nx-dev/ui-enterprise/src/lib/carousel.tsx b/nx-dev/ui-enterprise/src/lib/carousel.tsx new file mode 100644 index 00000000000000..8b6dbe89fabb44 --- /dev/null +++ b/nx-dev/ui-enterprise/src/lib/carousel.tsx @@ -0,0 +1,309 @@ +import { + createContext, + forwardRef, + ReactElement, + ReactNode, + Ref, + useCallback, + useContext, + useEffect, + useImperativeHandle, + useRef, + useState, +} from 'react'; +import { motion, MotionConfig, useAnimation } from 'framer-motion'; +import { cx } from '@nx/nx-dev/ui-primitives'; + +export interface CarouselHandle { + /** + * Navigate to a specific slide index + * @param index The zero-based index of the target slide + */ + goToSlide: (index: number) => void; + + /** + * Move to the next slide + */ + goToNext: () => void; + + /** + * Move to the previous slide + */ + goToPrevious: () => void; + + /** + * Get the current slide index + */ + getCurrentIndex: () => number; + + /** + * Get the total number of slides + */ + getTotalSlides: () => number; + + /** + * Pause the autoplay if it's enabled + */ + pauseAutoPlay: () => void; + + /** + * Resume the autoplay if it's enabled + */ + resumeAutoPlay: () => void; +} + +interface CarouselContextValue { + currentIndex: number; + totalSlides: number; + goToSlide: (index: number) => void; + goToNext: () => void; + goToPrevious: () => void; + pauseAutoPlay: () => void; + resumeAutoPlay: () => void; + registerSlide: (id: string) => void; + unregisterSlide: (id: string) => void; +} + +interface CarouselRootProps { + children: ReactNode; + className?: string; + autoPlayInterval?: number; + animationDuration?: number; + onSlideChange?: (index: number) => void; + enableKeyboardNavigation?: boolean; + ref?: Ref; +} + +const SPRING_CONFIG = { + type: 'spring' as const, + damping: 30, + stiffness: 300, + mass: 0.2, +}; + +const CarouselContext = createContext(null); + +export const useCarousel = (): CarouselContextValue => { + const context = useContext(CarouselContext); + if (!context) { + throw new Error('Carousel components must be used within a CarouselRoot'); + } + return context; +}; + +export const CarouselRoot = forwardRef( + ( + { + children, + className = '', + autoPlayInterval, + animationDuration = 0.5, + onSlideChange, + enableKeyboardNavigation = true, + }, + ref + ): ReactElement => { + const [currentIndex, setCurrentIndex] = useState(0); + const [slideIds, setSlideIds] = useState([]); + + const autoPlayTimeoutRef = useRef(); + const containerRef = useRef(null); + + const goToSlide = useCallback( + (index: number) => { + // Ensure the index is within bounds + const safeIndex = Math.max(0, Math.min(index, slideIds.length - 1)); + setCurrentIndex(safeIndex); + + // Call the onSlideChange callback if provided + onSlideChange?.(safeIndex); + }, + [slideIds.length, onSlideChange] + ); + const goToNext = useCallback(() => { + goToSlide((currentIndex + 1) % slideIds.length); + }, [currentIndex, slideIds.length, goToSlide]); + const goToPrevious = useCallback(() => { + goToSlide((currentIndex - 1 + slideIds.length) % slideIds.length); + }, [currentIndex, slideIds.length, goToSlide]); + + // Implement keyboard navigation + useEffect(() => { + if (!enableKeyboardNavigation) return; + + const handleKeyDown = (event: KeyboardEvent) => { + // Ignore keyboard navigation when user is typing in an input + if ( + event.target instanceof HTMLInputElement || + event.ctrlKey || + event.altKey || + event.shiftKey || + event.metaKey + ) { + return; + } + + switch (event.key) { + case 'ArrowLeft': + event.preventDefault(); + goToPrevious(); + break; + case 'ArrowRight': + event.preventDefault(); + goToNext(); + break; + case 'Home': + event.preventDefault(); + goToSlide(0); + break; + case 'End': + event.preventDefault(); + goToSlide(slideIds.length - 1); + break; + default: + break; + } + }; + + window.addEventListener('keydown', handleKeyDown); + return () => window.removeEventListener('keydown', handleKeyDown); + }, [ + enableKeyboardNavigation, + goToNext, + goToPrevious, + goToSlide, + slideIds.length, + ]); + + // Autoplay functionality + const pauseAutoPlay = useCallback(() => { + if (autoPlayTimeoutRef.current) { + clearInterval(autoPlayTimeoutRef.current); + } + }, []); + const resumeAutoPlay = useCallback(() => { + if (autoPlayInterval) { + pauseAutoPlay(); + autoPlayTimeoutRef.current = setInterval(goToNext, autoPlayInterval); + } + }, [autoPlayInterval, goToNext, pauseAutoPlay]); + + // Set up and clean up autoplay + useEffect(() => { + if (autoPlayInterval) { + resumeAutoPlay(); + } + return pauseAutoPlay; + }, [autoPlayInterval, resumeAutoPlay, pauseAutoPlay]); + + // Register and unregister slides + const registerSlide = useCallback((id: string) => { + setSlideIds((prev) => [...prev, id]); + }, []); + const unregisterSlide = useCallback((id: string) => { + setSlideIds((prev) => prev.filter((slideId) => slideId !== id)); + }, []); + + const contextValue = { + currentIndex, + totalSlides: slideIds.length, + goToSlide, + goToNext, + goToPrevious, + pauseAutoPlay, + resumeAutoPlay, + registerSlide, + unregisterSlide, + }; + + // Expose methods through the ref + useImperativeHandle( + ref, + () => ({ + goToSlide, + goToNext, + goToPrevious, + getCurrentIndex: () => currentIndex, + getTotalSlides: () => slideIds.length, + pauseAutoPlay, + resumeAutoPlay, + }), + [ + goToSlide, + goToNext, + goToPrevious, + currentIndex, + slideIds.length, + pauseAutoPlay, + resumeAutoPlay, + ] + ); + + return ( + + +
+ {children} +
+
+
+ ); + } +); + +export function CarouselViewport({ + className = '', + children, +}: { + className?: string; + children: ReactNode; +}): ReactElement { + const { currentIndex } = useCarousel(); + const controls = useAnimation(); + + useEffect(() => { + controls.start({ + x: -currentIndex * 100 + '%', + transition: SPRING_CONFIG, + }); + }, [currentIndex, controls]); + + return ( + + {children} + + ); +} + +export function CarouselSlide({ + children, + className = '', +}: { + children: ReactNode; + className?: string; +}): ReactElement { + const { registerSlide, unregisterSlide } = useCarousel(); + const slideId = useRef(`slide-${Math.random()}`); + + useEffect(() => { + registerSlide(slideId.current); + return () => unregisterSlide(slideId.current); + }, [registerSlide, unregisterSlide]); + + return ( +
+ {children} +
+ ); +} diff --git a/nx-dev/ui-enterprise/src/lib/customer-logos.tsx b/nx-dev/ui-enterprise/src/lib/customer-logos.tsx new file mode 100644 index 00000000000000..794d6a4bc813e7 --- /dev/null +++ b/nx-dev/ui-enterprise/src/lib/customer-logos.tsx @@ -0,0 +1,114 @@ +import { + AmericanAirlinesIcon, + AwsIcon, + BillIcon, + CapitalOneIcon, + CaterpillarIcon, + CiscoIcon, + FicoIcon, + HiltonIcon, + ManIcon, + RoyalBankOfCanadaIcon, + SevenElevenIcon, + ShopifyIcon, + StorybookIcon, + VmwareIcon, +} from '@nx/nx-dev/ui-icons'; +import { ReactElement } from 'react'; +import { Marquee } from '@nx/nx-dev/ui-animations'; +import { cx } from '@nx/nx-dev/ui-primitives'; +import Link from 'next/link'; +import { ChevronRightIcon } from '@heroicons/react/20/solid'; + +export function CustomerLogos(): ReactElement { + const icons = [ + { + Icon: AwsIcon, + className: 'size-14', + }, + { + Icon: ManIcon, + className: 'size-14', + }, + { + Icon: CapitalOneIcon, + className: 'size-28', + }, + { + Icon: ShopifyIcon, + className: null, + }, + { + Icon: RoyalBankOfCanadaIcon, + className: null, + }, + { + Icon: VmwareIcon, + className: 'size-24', + }, + { + Icon: StorybookIcon, + className: null, + }, + { + Icon: FicoIcon, + className: 'size-20', + }, + { + Icon: CaterpillarIcon, + className: null, + }, + { + Icon: CiscoIcon, + className: 'size-16', + }, + { + Icon: BillIcon, + className: null, + }, + { + Icon: SevenElevenIcon, + className: null, + }, + { + Icon: HiltonIcon, + className: 'size-24', + }, + { + Icon: AmericanAirlinesIcon, + className: null, + }, + ]; + + return ( +
+ + {icons.map((e, idx) => ( + +
+
+
+ + See our customers{' '} +
+
+ ); +} diff --git a/nx-dev/ui-enterprise/src/lib/customer-metrics.tsx b/nx-dev/ui-enterprise/src/lib/customer-metrics.tsx new file mode 100644 index 00000000000000..503688fbeeb4dd --- /dev/null +++ b/nx-dev/ui-enterprise/src/lib/customer-metrics.tsx @@ -0,0 +1,90 @@ +import { ReactElement } from 'react'; +import { HetznerCloudIcon } from '@nx/nx-dev/ui-icons'; +import { SectionHeading } from '@nx/nx-dev/ui-common'; +import Link from 'next/link'; +import { sendCustomEvent } from '@nx/nx-dev/feature-analytics'; + +export function CustomerMetrics(): ReactElement { + return ( +
+
+
+
+
+
+
+

+ Engineers will run a test command and expect it to run for + 20 mins, they start it and see it finishes in a few seconds, + then they ask “Did I start it wrong? Why is it so fast?” +

+
+
+ pavlo grosse +
+
Pavlo Grosse
+
+ Senior Software Engineer, Hetzner Cloud +
+
+
+
+ + Want to see it in action?{' '} + + sendCustomEvent( + 'request-trial-click', + 'enterprise-customer-metrics', + 'enterprise' + ) + } + className="font-semibold underline" + > + Request a demo now + + +
+
+
+
+
faster CI
+
+ 70% +
+
+
+
less compute used
+
+ 60% +
+
+
+
reduction in infra costs
+
+ 75% +
+
+
+
+
+
+
+
+ ); +} diff --git a/nx-dev/ui-enterprise/src/lib/download-case-study.tsx b/nx-dev/ui-enterprise/src/lib/download-case-study.tsx index c89f8820d03f82..4479f2725731de 100644 --- a/nx-dev/ui-enterprise/src/lib/download-case-study.tsx +++ b/nx-dev/ui-enterprise/src/lib/download-case-study.tsx @@ -1,4 +1,5 @@ import { ButtonLink } from '@nx/nx-dev/ui-common'; +import { ReactElement } from 'react'; export interface DownloadCaseStudyProps { title: string; @@ -12,7 +13,7 @@ export function DownloadCaseStudy({ description, buttonHref, buttonText = 'Download (pdf)', -}: DownloadCaseStudyProps): JSX.Element { +}: DownloadCaseStudyProps): ReactElement { return (
diff --git a/nx-dev/ui-enterprise/src/lib/download-ebook.tsx b/nx-dev/ui-enterprise/src/lib/download-ebook.tsx deleted file mode 100644 index 6cf77ffecf509e..00000000000000 --- a/nx-dev/ui-enterprise/src/lib/download-ebook.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import { ButtonLink } from '@nx/nx-dev/ui-common'; -import { ReactElement } from 'react'; - -export function DownloadEbook(): ReactElement { - return ( -
-
- -
-

- Download our ebook -

-

- Discover how to scale your organization without feeling the pain of - CI, while having a better developer experience and fitting your - requirements. -

-
- - Download{' '} - (pdf) - -
-
-
- App screenshot - - ebook - -
-
-
- ); -} diff --git a/nx-dev/ui-enterprise/src/lib/enterprise-addons.tsx b/nx-dev/ui-enterprise/src/lib/enterprise-addons.tsx deleted file mode 100644 index 7fde9872ff3992..00000000000000 --- a/nx-dev/ui-enterprise/src/lib/enterprise-addons.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import { - BoltIcon, - ChevronDoubleRightIcon, - UsersIcon, -} from '@heroicons/react/24/outline'; -import { SectionHeading } from '@nx/nx-dev/ui-common'; - -export function EnterpriseAddons(): JSX.Element { - return ( -
-
-
- - Partner with the Nx team - -
-
-
-
-
-
-
- Move fast, move together -
-
-

- We know Nx, you know your code. Together, we can build your - ultimate developer platform, tailored to your team. -

-
-
-
-
-
-
- No trial and error necessary -
-
-

- With the help of the developers of Nx, you'll use Nx and Nx - Cloud to its full potential, the first time. No matter how - long you've been using Nx, we'll find ways to make it more - powerful. -

-
-
-
-
-
-
- Migrate to Nx & Nx Cloud -
-
-

- Wherever your team is at in their Nx journey, our experts will - make it easy to move ahead and capture the full value of Nx - and Nx Cloud. -

-
-
-
-
-
-
- ); -} diff --git a/nx-dev/ui-enterprise/src/lib/hero.tsx b/nx-dev/ui-enterprise/src/lib/hero.tsx index 30d0a939d23048..d122f38c889bb7 100644 --- a/nx-dev/ui-enterprise/src/lib/hero.tsx +++ b/nx-dev/ui-enterprise/src/lib/hero.tsx @@ -1,42 +1,104 @@ import { ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common'; -import Link from 'next/link'; +import { ReactElement } from 'react'; +import { ChevronRightIcon } from '@heroicons/react/20/solid'; +import { sendCustomEvent } from '@nx/nx-dev/feature-analytics'; -export function Hero(): JSX.Element { +export function Hero(): ReactElement { return ( -
-
-
- - Nx Enterprise +
+ +
+
+

+ + + Live event + + + Webinar + live Q&A on Dec 10th + + +

+ + Solving the Performance Paradox,{' '} + + get speed and scale + Accelerate your organization's journey to tighter collaboration, better developer experience, and speed…lots of speed. -
+
+ sendCustomEvent( + 'request-trial-click', + 'enterprise-hero', + 'enterprise' + ) + } > Request a free trial -

- Got questions?{' '} - - Talk to an engineer. - -

+
+
+
+
+
+ nx cloud application dashboard screenshot +
diff --git a/nx-dev/ui-enterprise/src/lib/hetzner-cloud-testimonial.tsx b/nx-dev/ui-enterprise/src/lib/hetzner-cloud-testimonial.tsx new file mode 100644 index 00000000000000..3a3f0d0a18c222 --- /dev/null +++ b/nx-dev/ui-enterprise/src/lib/hetzner-cloud-testimonial.tsx @@ -0,0 +1,246 @@ +import { ComponentProps, ReactElement } from 'react'; +import { Button, ButtonLink, SectionHeading } from '@nx/nx-dev/ui-common'; +import { HetznerCloudIcon } from '@nx/nx-dev/ui-icons'; +import Link from 'next/link'; +import { cx } from '@nx/nx-dev/ui-primitives'; +import { MovingBorder } from '@nx/nx-dev/ui-animations'; +import { motion } from 'framer-motion'; +import { + ArrowDownTrayIcon, + PlayIcon, + VideoCameraIcon, +} from '@heroicons/react/24/outline'; + +function PlayButton({ + className, + ...props +}: ComponentProps<'div'>): ReactElement { + const parent = { + initial: { + width: 82, + transition: { + when: 'afterChildren', + }, + }, + hover: { + width: 296, + transition: { + duration: 0.125, + type: 'tween', + ease: 'easeOut', + }, + }, + }; + const child = { + initial: { + opacity: 0, + x: -6, + }, + hover: { + x: 0, + opacity: 1, + transition: { + duration: 0.015, + type: 'tween', + ease: 'easeOut', + }, + }, + }; + + return ( +
+
+ +
+ +
+ + +
+ ); +} + +export function HetznerCloudTestimonial(): ReactElement { + return ( +
+
+ + Nx Enterprise{' '} + + speeds build and test times + {' '} +
+ as Hetzner Cloud{' '} + + scales up + {' '} + product offering +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + Avatar + +
+ {/* setIsOpen(true)}*/} + {/*/>*/} +
+
+
+ +
+
+ + +
+

+ Featured client +

+ +

+ Nx is speed and scalability. Before we only had a few features + and CI was slow and now it’s fast with way more features. + That’s a huge win for us.”. +

+
+ +
+ pavlo grosse +
+
Pavlo Grosse
+
+ Senior Software Engineer, Hetzner Cloud +
+
+
+ +
+ {/**/} + {/*
+
+
+
+
+
+ ); +} diff --git a/nx-dev/ui-enterprise/src/lib/make-your-ci-fast.tsx b/nx-dev/ui-enterprise/src/lib/make-your-ci-fast.tsx new file mode 100644 index 00000000000000..5e99098dca1008 --- /dev/null +++ b/nx-dev/ui-enterprise/src/lib/make-your-ci-fast.tsx @@ -0,0 +1,143 @@ +import { ReactElement } from 'react'; +import { SectionHeading } from '@nx/nx-dev/ui-common'; + +export function MakeYourCiFast(): ReactElement { + return ( +
+
+ + Make your CI fast,{' '} + + really fast + + +
+
+
+ Nx Replay: remote caching +
+
+ + Nx Replay + +
+

+ Never build the same code twice +

+

+ Remote caching ensures that tasks are never rebuilt twice, + significantly reducing build times and resource usage. Share + cached results across your team and CI pipelines. +

+
+
+
+
+
+ Nx flaky task detection & rerun +
+
+ + Flaky task retries + +
+

+ One less thing to debug +

+

+ Automatically detects and re-runs flaky tasks, enhancing the + reliability of your CI processes and minimize time spent + debugging. +

+
+
+
+
+
+ Nx Atomizer: split large tasks & E2E in chunks +
+
+ + Atomizer + +
+

+ Break tasks down, to speed tests up +

+

+ Atomizer automatically + splits large e2e tests into smaller, atomized tasks, enabling + lightening fast testing. Parallelize your tests to reduce + bottlenecks and keep your pipelines fast. +

+
+
+
+
+
+ Nx Agents: simple & fast task distribution +
+
+ + Nx Agents + +
+

+ Machines, make it fast! +

+

+ Nx Agents intelligently + distribute tasks across multiple machines, significantly + reducing build times. Dynamically allocate agents based on PR + size to balance speed and cost. +

+
+
+
+
+
+ Partner with the Nx Team for guidances +
+
+ + Partnership + +
+

+ Always thinking a step ahead for you +

+

+ With Nx, you receive expert guidance from day one, ensuring + your setup is optimized for maximum efficiency. Whether you're + starting fresh, migrating, or scaling your developer platform, + we'll work with you to tailor the perfect solution for your + team. +

+
+
+
+
+
+
+ ); +} diff --git a/nx-dev/ui-enterprise/src/lib/metrics-and-customers.tsx b/nx-dev/ui-enterprise/src/lib/metrics-and-customers.tsx deleted file mode 100644 index d31eefdf2751d4..00000000000000 --- a/nx-dev/ui-enterprise/src/lib/metrics-and-customers.tsx +++ /dev/null @@ -1,185 +0,0 @@ -import { motion, Variants } from 'framer-motion'; -import { DownloadCaseStudy } from './download-case-study'; -import { - BillColoredIcon, - CapitalOneIcon, - CaterpillarIcon, - CiscoIcon, - FicoIcon, - HiltonIcon, - ManIcon, - RoyalBankOfCanadaColoredIcon, - SevenElevenColoredIcon, - ShopifyIcon, - StorybookIcon, - VmwareIcon, -} from '@nx/nx-dev/ui-icons'; - -export function MetricsAndCustomers(): JSX.Element { - const downloadElement: Variants = { - hidden: { - opacity: 0, - translateY: 90, - }, - visible: { - opacity: 1, - translateY: 0, - transition: { - duration: 1, - ease: 'easeInOut', - type: 'tween', - }, - }, - }; - return ( -
- -
-
-
-
Speed
-
- - 30-70% Faster - -
-
-
-
Infra Cost
-
- - 40-75% Cheaper - -
-
-
-
Compute
-
- - 30-60% Less - -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - - -
-
-
-
-
-
-
-
-
-
- ); -} diff --git a/nx-dev/ui-enterprise/src/lib/scale-your-organization.tsx b/nx-dev/ui-enterprise/src/lib/scale-your-organization.tsx new file mode 100644 index 00000000000000..fb7e70b236bbe4 --- /dev/null +++ b/nx-dev/ui-enterprise/src/lib/scale-your-organization.tsx @@ -0,0 +1,317 @@ +import { ReactElement } from 'react'; +import { SectionHeading, Strong } from '@nx/nx-dev/ui-common'; +import { + AcademicCapIcon, + ArrowPathIcon, + CheckBadgeIcon, + CodeBracketSquareIcon, + DocumentMagnifyingGlassIcon, + DocumentTextIcon, + EyeIcon, + ShieldExclamationIcon, + UsersIcon, +} from '@heroicons/react/24/outline'; +import Link from 'next/link'; + +export function ScaleYourOrganization(): ReactElement { + return ( +
+
+
+
+ Nx Polygraph +
+
+
+ + Get to market faster by avoiding the most common pitfall of + growing teams: silos. Silos create waste, have poorly defined + ownership, lack visibility - and slow everything down. + + + Polygraph is a set of Nx Enterprise features built to help large + organizations{' '} + + see across workspaces and take action to accelerate + time-to-market + + . + +
+
+

+ “Nx means tooling and efficiency around our software + development lifecycle that empowers us to move a lot faster, + ship code faster and more reliably.” +

+
+
+ Justin Schwartzenberger +
+
Justin Schwartzenberger
+
+ Principle Software Engineer, SiriusXM +
+
+
+
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Visibility +
+
+ See dependencies across team and repos +
+
+

+ In an organization with hundreds of repos it can be hard + to understand the relationships between different parts of + your ever-growing codebases. With the Workspace Graph, see + dependencies across all your repos to understand which + projects and teams are affected by changes in a single + repo. +

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Conformance +
+
+ Streamline onboarding and governance +
+
+

+ Platform teams can easily publish and enforce coding + standards across an entire organization. Write and publish + rules, refactorings, and generators, then quickly deploy + them across all repos without involving individual teams. + Ensure security vulnerabilities are always addressed and + third-party dependencies stay up to date.{' '} + + Included in{' '} + + Nx Powerpack + + , available complimentary to all Enterprise customers. + +

+
    +
  • + + Configure Conformance Rules{' '} + + +
  • +
  • + + Publish Conformance Rules{' '} + + +
  • +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Ownership +
+
+ Clear, expressive ownership +
+
+

+ Unlike the code ownership tools from VCS provides, Nx + Owners is built for monorepos. Define ownership at the + project level. Nx will compile it back to the file-based + rules your VCS providers understand. +

+

+ Polygraph lets you see owners across all your repositories + and plan out multi repo refactorings and migrations.{' '} + + Included in{' '} + + Nx Powerpack + + , available complimentary to all Enterprise customers. + +

+
+
+
+
+
+
+
+
+ ); +} + +export function ScaleOrganizationIntro(): ReactElement { + return ( +
+ +
+ + Don’t lose output as your organization grows{' '} +
+ 10x developer{' '} + + Nx developers are even more efficient at scale + +
+
+
+ ); +} diff --git a/nx-dev/ui-enterprise/src/lib/scale-your-people.tsx b/nx-dev/ui-enterprise/src/lib/scale-your-people.tsx deleted file mode 100644 index a20f61ce61c267..00000000000000 --- a/nx-dev/ui-enterprise/src/lib/scale-your-people.tsx +++ /dev/null @@ -1,255 +0,0 @@ -import { - BuildingOffice2Icon, - Cog6ToothIcon, - CubeTransparentIcon, - IdentificationIcon, - SquaresPlusIcon, - UserGroupIcon, -} from '@heroicons/react/24/outline'; -import { SectionHeading } from '@nx/nx-dev/ui-common'; - -export function ScaleYourPeople(): JSX.Element { - return ( -
-
-
- - Scale your people - -
- - Build big things with the efficiency of a small team by increasing - collaboration and developer mobility, reducing wait time and - duplication, and establishing clear ownership. - -
-
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- - Product screenshot - -
- - -
-
- - coming soon - -
-
-
- -
-
-

- Monorepo, polyrepo, multi-monorepo? -

-

- Whatever you’re working with, Nx Enterprise will give you the - visibility you need to understand what they have in common, - how they relate, and how they differ. -

-
-
-
-
- -
-
-

- Monorepo experience in a polyrepo environment -

-

- Nx Enterprise will support optional monorepo-like constraints - to be applied across Nx Workspace boundaries in a seamless and - flexible way. Move fast with confidence. -

-
-
-
-
- -
-
-

- Automation over coordination -

-

- Testing and cross-repo coordination can be left to Nx - Enterprise tooling instead of manual human intervention to - test and enforce cross-repo dependencies & constraints. -

-
-
-
-
-
-
- ); -} diff --git a/nx-dev/ui-enterprise/src/lib/security.tsx b/nx-dev/ui-enterprise/src/lib/security.tsx index ddc83ac35858a6..b5864741514066 100644 --- a/nx-dev/ui-enterprise/src/lib/security.tsx +++ b/nx-dev/ui-enterprise/src/lib/security.tsx @@ -1,10 +1,16 @@ +import { + GlobeAmericasIcon, + ServerStackIcon, + ShieldCheckIcon, +} from '@heroicons/react/24/outline'; import { SectionHeading } from '@nx/nx-dev/ui-common'; +import { ReactElement } from 'react'; -export function Security(): JSX.Element { +export function Security(): ReactElement { return (
-
-
+
+
Security @@ -62,35 +68,49 @@ export function Security(): JSX.Element {
-
-

- Dedicated infrastructure -

-

- We can support you to self-host Nx Cloud within your own - infrastructure or, depending on your needs, run Nx Cloud on - managed hosts within our cloud. -

+
+
-
-

- Application security -

-

- We consistently review our security policies and collaborate - with third parties for penetration testing to promptly identify - and mitigate potential risks. -

+ +
+
-
-

- US & EU instances available -

-

- We support region specific hosting of Nx Cloud in the event IT - security or data protection policies restrict international - transfers. -

+ +
+
@@ -100,7 +120,7 @@ export function Security(): JSX.Element { aria-hidden="true" >
-
-
- - Solve your CI - -
- - Monorepos help you scale your people but they can also make CI a - challenge. Nx Enterprise solves it by providing efficient, fast and - reliable CI that can handle workflows of any size. - - {/*FEATURES CONTAINER*/} - - {items.map((item, i) => ( - p:text-lg]', item.className)} - icon={item.icon} - url={item.url} - /> - ))} - - - {/*TEXT*/} -
- - - -
-
-
- -
-
-

- Both faster and cheaper -

-

- Current CI providers aren’t made for monorepos. They’re - low-level and static in their configuration. The combination - of Nx Agents and Nx Replay lets you reuse computation from - other runs and utilizes the allocated VMs in the most optimal - way. -

-
-
-
-
- -
-
-

- Solving E2E tests -

-

- Atomizer splits large e2e projects into fine-grained test - runs, enabling more efficient distribution and dramatically - reducing CI times. It also identifies flaky e2e tests at the - file level and re-runs those specific tests. -

-
-
-
-
- -
-
-

- What, not how -

-

- Nx Enterprise simplifies CI configuration, emphasizing which - tasks to execute over how with no need to tweak your CI - scripts as your monorepo evolves. This simplified - configuration cuts down on CI maintenance and increases - stability. -

-
-
-
-
- -
-
-

- Nx Powerpack included -

-

- A suite of paid extensions for the Nx CLI specifically - designed for enterprises, built and supported by the Nx core - team.{' '} - - Learn more about Nx Powerpack → - -

-
-
-
-
-
-
- ); -} - -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 ( - - - -
- {items.map((i, idx) => ( -
-
-
- - {i.cache} - -
-
- {i.project}:{i.target} -
-
< 1s
-
- ))} -
- - ); -}; - -const Atomizer = () => { - const variants = { - hidden: { - opacity: 0, - transition: { - when: 'afterChildren', - }, - }, - visible: { - opacity: 1, - }, - }; - const itemVariants = { - visible: (i: number) => ({ - opacity: 1, - x: 0, - transition: { - delay: i * 0.2, - duration: 0.275, - ease: 'easeOut', - when: 'beforeChildren', - staggerChildren: 0.3, - }, - }), - hidden: { - opacity: 0, - x: -100, - transition: { - when: 'afterChildren', - }, - }, - }; - const uiDialogsTests = ['e2e-ui-cdk:e2e', 'e2e-ui-layout:e2e']; - const loansTests = [ - 'loans-front-store:e2e', - 'loans-loans:e2e', - 'loans-credit-card:e2e', - 'loans-workflows:e2e', - 'loans-mortgage:e2e', - 'loans-submission:e2e', - ]; - const DefaultConnector = () => ( - <> -