|
| 1 | +import React from 'react'; |
| 2 | +import styles from './NexusDemo.module.css'; |
| 3 | + |
| 4 | +type Props = { onNext: () => void }; |
| 5 | + |
| 6 | +const components = [ |
| 7 | + { |
| 8 | + tag: 'tagBlue' as const, |
| 9 | + tagLabel: 'Endpoint', |
| 10 | + title: 'Nexus Endpoint', |
| 11 | + desc: 'A named, versioned router configured in the Temporal control plane. It maps a name (e.g. "fraud-service-endpoint") to a target namespace and task queue. This is the only thing Team A needs to know about Team B\'s infrastructure.', |
| 12 | + example: '"my-nexus-endpoint"', |
| 13 | + }, |
| 14 | + { |
| 15 | + tag: 'tagPurple' as const, |
| 16 | + tagLabel: 'Service', |
| 17 | + title: 'Nexus Service', |
| 18 | + desc: 'A named collection of operations defined by an interface (Go) or decorated class (TypeScript, .NET). Think of it like a gRPC service definition or a typed REST API contract — it describes what\'s callable without exposing how.', |
| 19 | + example: '[NexusService] IHelloService', |
| 20 | + }, |
| 21 | + { |
| 22 | + tag: 'tagGreen' as const, |
| 23 | + tagLabel: 'Operation', |
| 24 | + title: 'Nexus Operation', |
| 25 | + desc: 'A single callable unit within a service. Operations are either synchronous (run inline, return in < 10s) or asynchronous (start a Temporal Workflow, can run for days). The caller\'s code looks the same either way — just await the result.', |
| 26 | + example: 'Echo() | SayHello()', |
| 27 | + }, |
| 28 | + { |
| 29 | + tag: 'tagBlue' as const, |
| 30 | + tagLabel: 'Registry', |
| 31 | + title: 'Nexus Registry', |
| 32 | + desc: 'The Temporal Cloud control plane (or OSS server config) that stores endpoint definitions, access policies, and routing rules. Admins configure which caller namespaces can reach which handler namespaces through which endpoints.', |
| 33 | + example: 'Temporal Cloud UI / tcld', |
| 34 | + }, |
| 35 | +]; |
| 36 | + |
| 37 | +export default function ComponentsSection({ onNext }: Props) { |
| 38 | + return ( |
| 39 | + <div className={styles.section}> |
| 40 | + <div className={styles.progressBar}> |
| 41 | + <div className={styles.progressFill} style={{ width: '28%' }} /> |
| 42 | + </div> |
| 43 | + |
| 44 | + <h1>The Four Building Blocks</h1> |
| 45 | + <p className={styles.lead}> |
| 46 | + Nexus is composed of four concepts. Once you understand these, the rest falls into place. |
| 47 | + </p> |
| 48 | + |
| 49 | + <div className={styles.cardGrid}> |
| 50 | + {components.map((c) => ( |
| 51 | + <div key={c.title} className={styles.card}> |
| 52 | + <div className={`${styles.tag} ${styles[c.tag]}`}>{c.tagLabel}</div> |
| 53 | + <h3 style={{ fontSize: 15, marginBottom: 8 }}>{c.title}</h3> |
| 54 | + <p style={{ fontSize: 13, color: 'var(--nd-muted)', margin: '0 0 10px', lineHeight: 1.6 }}> |
| 55 | + {c.desc} |
| 56 | + </p> |
| 57 | + <code |
| 58 | + style={{ |
| 59 | + fontSize: 11, |
| 60 | + color: 'var(--nd-muted)', |
| 61 | + background: 'var(--nd-surface2)', |
| 62 | + padding: '2px 6px', |
| 63 | + borderRadius: 4, |
| 64 | + }} |
| 65 | + > |
| 66 | + {c.example} |
| 67 | + </code> |
| 68 | + </div> |
| 69 | + ))} |
| 70 | + </div> |
| 71 | + |
| 72 | + <h2 className={styles.sectionHeading}>Nexus vs. the Alternatives</h2> |
| 73 | + <table className={styles.table}> |
| 74 | + <thead> |
| 75 | + <tr> |
| 76 | + <th>Approach</th> |
| 77 | + <th>Durable</th> |
| 78 | + <th>Typed contract</th> |
| 79 | + <th>Cross-namespace</th> |
| 80 | + <th>Auto-retry</th> |
| 81 | + <th>Cancel propagation</th> |
| 82 | + </tr> |
| 83 | + </thead> |
| 84 | + <tbody> |
| 85 | + {[ |
| 86 | + { |
| 87 | + name: 'Shared namespace', |
| 88 | + durable: true, |
| 89 | + typed: false, |
| 90 | + cross: false, |
| 91 | + retry: true, |
| 92 | + cancel: false, |
| 93 | + }, |
| 94 | + { |
| 95 | + name: 'HTTP between teams', |
| 96 | + durable: false, |
| 97 | + typed: false, |
| 98 | + cross: true, |
| 99 | + retry: false, |
| 100 | + cancel: false, |
| 101 | + }, |
| 102 | + { |
| 103 | + name: 'Child workflows', |
| 104 | + durable: true, |
| 105 | + typed: true, |
| 106 | + cross: false, |
| 107 | + retry: true, |
| 108 | + cancel: true, |
| 109 | + }, |
| 110 | + { |
| 111 | + name: 'Temporal Nexus', |
| 112 | + durable: true, |
| 113 | + typed: true, |
| 114 | + cross: true, |
| 115 | + retry: true, |
| 116 | + cancel: true, |
| 117 | + highlight: true, |
| 118 | + }, |
| 119 | + ].map((row) => ( |
| 120 | + <tr key={row.name} style={row.highlight ? { background: 'var(--nd-primary-bg)' } : {}}> |
| 121 | + <td style={{ fontWeight: row.highlight ? 700 : 400 }}>{row.name}</td> |
| 122 | + <td className={row.durable ? styles.check : styles.cross}> |
| 123 | + {row.durable ? '✓' : '—'} |
| 124 | + </td> |
| 125 | + <td className={row.typed ? styles.check : styles.cross}> |
| 126 | + {row.typed ? '✓' : '—'} |
| 127 | + </td> |
| 128 | + <td className={row.cross ? styles.check : styles.cross}> |
| 129 | + {row.cross ? '✓' : '—'} |
| 130 | + </td> |
| 131 | + <td className={row.retry ? styles.check : styles.cross}> |
| 132 | + {row.retry ? '✓' : '—'} |
| 133 | + </td> |
| 134 | + <td className={row.cancel ? styles.check : styles.cross}> |
| 135 | + {row.cancel ? '✓' : '—'} |
| 136 | + </td> |
| 137 | + </tr> |
| 138 | + ))} |
| 139 | + </tbody> |
| 140 | + </table> |
| 141 | + |
| 142 | + <div className={styles.nextRow}> |
| 143 | + <button className={styles.btn} onClick={onNext}> |
| 144 | + Next: How It Works → |
| 145 | + </button> |
| 146 | + </div> |
| 147 | + </div> |
| 148 | + ); |
| 149 | +} |
0 commit comments