diff --git a/MARKDOWN_PIPELINE.md b/MARKDOWN_PIPELINE.md index aa71a5ef57..4fb4b9afde 100644 --- a/MARKDOWN_PIPELINE.md +++ b/MARKDOWN_PIPELINE.md @@ -122,7 +122,7 @@ Each component maps to a strategy in `COMPONENT_REGISTRY` (in `scripts/mdx-to-md | `QuickstartCards`, `PatternCards` | `cards` | Markdown link list parsed from the inline `items={[{href,title,description}]}` prop | | `ZoomPanPinch` | `transparent` | Wrapper stripped; inner content passed through | | `DocCardList`, `CardList`, `LandingCard`, `ThemedImage`, `SdkSvg`, `CloudRegionCount`, `RetrySimulator`, `ServerlessWorkerDemo`, `OperationsTable`, `InvitationContent` | `strip-block` | Removed entirely (visual/dynamic, no extractable text) | -| `DL`, `DT`, `DD`, `DefinitionList` | `strip-tag` | Tags stripped, text content kept | +| `DL`, `DT`, `DD`, `DefinitionList`, `AnnotatedCode` | `strip-tag` | Tags stripped, text content kept | | `details` / `summary` | `details` / `summary` | `` becomes a heading; body expanded inline | **Transclusion.** Components imported from a Markdown file diff --git a/docs/design-patterns/child-workflows.mdx b/docs/design-patterns/child-workflows.mdx index 0923c743b6..9c5c83eab3 100644 --- a/docs/design-patterns/child-workflows.mdx +++ b/docs/design-patterns/child-workflows.mdx @@ -7,6 +7,7 @@ description: "Decomposes complex Workflows into smaller, reusable units. Each ch import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; +import { AnnotatedCode } from '@site/src/components'; ## Overview @@ -167,13 +168,33 @@ In Go, `workflow.ExecuteChildWorkflow()` returns a `ChildWorkflowFuture`, and ca ### Asynchronous Child Workflow The following example starts a Child Workflow asynchronously with an ABANDON policy. -The parent receives the child's execution info without waiting for completion: +The parent receives the child's execution info without waiting for completion. Select a concept to highlight the matching lines: - + ```python -# workflows.py from temporalio import workflow from temporalio.workflow import ParentClosePolicy @@ -183,7 +204,6 @@ from child_workflows import ChildWorkflow class ParentWorkflow: @workflow.run async def run(self, input: str) -> str: - # Async call - returns handle once child starts handle = await workflow.start_child_workflow( ChildWorkflow.run, input, @@ -191,20 +211,34 @@ class ParentWorkflow: parent_close_policy=ParentClosePolicy.ABANDON, ) - # Parent continues without waiting for child completion return handle.id ``` - + - + ```go -// parent_workflow.go -import ( - enumspb "go.temporal.io/api/enums/v1" - "go.temporal.io/sdk/workflow" -) - func ParentWorkflow(ctx workflow.Context, input string) (string, error) { cwo := workflow.ChildWorkflowOptions{ ParentClosePolicy: enumspb.PARENT_CLOSE_POLICY_ABANDON, @@ -213,22 +247,40 @@ func ParentWorkflow(ctx workflow.Context, input string) (string, error) { childFuture := workflow.ExecuteChildWorkflow(ctx, ChildWorkflow, input) - // Wait for child to start, not complete var childWE workflow.Execution if err := childFuture.GetChildWorkflowExecution().Get(ctx, &childWE); err != nil { return "", err } - // Parent continues without waiting for child completion return childWE.ID, nil } ``` - + - + ```java -// ParentWorkflowImpl.java public class ParentWorkflowImpl implements ParentWorkflow { @Override public WorkflowExecution execute(String input) { @@ -239,21 +291,39 @@ public class ParentWorkflowImpl implements ParentWorkflow { ChildWorkflow child = Workflow.newChildWorkflowStub(ChildWorkflow.class, options); - // Async call - returns immediately Async.function(child::processData, input); - // Get child execution info without waiting for completion Promise childExecution = Workflow.getWorkflowExecution(child); - return childExecution.get(); // Blocks only until child starts + return childExecution.get(); } } ``` - + - + ```typescript -// workflows.ts import { startChild, ParentClosePolicy } from '@temporalio/workflow'; import { childWorkflow } from './child-workflows'; @@ -263,12 +333,10 @@ export async function parentWorkflow(input: string): Promise { parentClosePolicy: ParentClosePolicy.PARENT_CLOSE_POLICY_ABANDON, }); - // Parent continues without waiting for child completion - // childHandle.workflowId and childHandle.firstExecutionRunId are available return childHandle.workflowId; } ``` - + diff --git a/docs/develop/environment-configuration.mdx b/docs/develop/environment-configuration.mdx index 67e1642320..76899159f8 100644 --- a/docs/develop/environment-configuration.mdx +++ b/docs/develop/environment-configuration.mdx @@ -11,7 +11,7 @@ tags: --- import { LANGUAGE_TAB_GROUP, getLanguageLabel } from '@site/src/constants/languageTabs'; -import { SdkTabs } from '@site/src/components'; +import { SdkTabs, AnnotatedCode } from '@site/src/components'; import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem'; @@ -93,6 +93,48 @@ MIIPrivateKeyDataHere... -----END PRIVATE KEY-----""" ``` +Select a concept to highlight the matching connection settings in a Cloud profile: + + +```toml +[profile.prod] +address = "your-namespace.a1b2c.tmprl.cloud:7233" +namespace = "your-namespace" +api_key = "your-api-key-here" + +[profile.prod.tls] +client_cert_path = "/etc/temporal/certs/client.pem" +client_key_path = "/etc/temporal/certs/client.key" +``` + + The [`temporal cloud login`](/cli/cloud#interactive-login) command also writes to this file. When you run `temporal cloud login --profile prod`, the OAuth token is stored in the specified profile automatically. Subsequent commands that use that profile read the token from the TOML file to authenticate with Temporal Cloud. ## CLI integration diff --git a/docs/develop/task-queue-priority-fairness.mdx b/docs/develop/task-queue-priority-fairness.mdx index 32ea26f4ce..95287c3ca6 100644 --- a/docs/develop/task-queue-priority-fairness.mdx +++ b/docs/develop/task-queue-priority-fairness.mdx @@ -14,7 +14,7 @@ tags: - Priority and Fairness --- -import { EnlargeImage, SdkTabs } from '@site/src/components'; +import { EnlargeImage, SdkTabs, AnnotatedCode } from '@site/src/components'; [Task Queue Priority](#task-queue-priority) and [Task Queue Fairness](#task-queue-fairness) are two ways to manage the distribution of work within a Task Queue. Priority allows [Tasks](/tasks) to be executed in Priority order. @@ -267,10 +267,32 @@ temporal workflow start \ --fairness-weight 3.14 ``` -You can set fairness keys and weights for a Workflow within the SDK like so: +You can set fairness keys and weights for a Workflow within the SDK like so. Select a concept to highlight the matching lines: + ```go workflowOptions := client.StartWorkflowOptions{ ID: "my-workflow-id", @@ -283,30 +305,107 @@ workflowOptions := client.StartWorkflowOptions{ } we, err := c.ExecuteWorkflow(context.Background(), workflowOptions, MyWorkflow) ``` + + ```java WorkflowOptions options = WorkflowOptions.newBuilder() .setTaskQueue("my-task-queue") - .setPriority(Priority.newBuilder().setPriorityKey(5).setFairnessKey("a-key").setFairnessWeight(3.14).build()) + .setPriority(Priority.newBuilder() + .setPriorityKey(5) + .setFairnessKey("a-key") + .setFairnessWeight(3.14) + .build()) .build(); WorkflowClient client = WorkflowClient.newInstance(service); MyWorkflow workflow = client.newWorkflowStub(MyWorkflow.class, options); workflow.run(); ``` + + ```python await client.start_workflow( MyWorkflow.run, args="hello", id="my-workflow-id", task_queue="my-task-queue", - priority=Priority(priority_key=3, fairness_key="a-key", fairness_weight=3.14), + priority=Priority( + priority_key=3, + fairness_key="a-key", + fairness_weight=3.14, + ), ) ``` + + ```ruby client.start_workflow( MyWorkflow, "input-arg", @@ -319,16 +418,66 @@ client.start_workflow( ) ) ``` + + ```ts const handle = await startWorkflow(workflows.priorityWorkflow, { args: [false, 1], - priority: { priorityKey: 3, fairnessKey: 'a-key', fairnessWeight: 3.14 }, + priority: { + priorityKey: 3, + fairnessKey: 'a-key', + fairnessWeight: 3.14, + }, }); ``` + + ```csharp var handle = await Client.StartWorkflowAsync( (MyWorkflow wf) => wf.RunAsync("hello"), @@ -345,6 +494,7 @@ var handle = await Client.StartWorkflowAsync( } ); ``` + diff --git a/docs/develop/worker-performance.mdx b/docs/develop/worker-performance.mdx index 22a0c5d7b2..6e8d9309bf 100644 --- a/docs/develop/worker-performance.mdx +++ b/docs/develop/worker-performance.mdx @@ -9,7 +9,7 @@ tags: - Performance --- -import { CaptionedImage, ReleaseNoteHeader, SdkTabs } from '@site/src/components'; +import { CaptionedImage, ReleaseNoteHeader, SdkTabs, AnnotatedCode } from '@site/src/components'; import { LANGUAGE_TAB_GROUP, getLanguageLabel } from '@site/src/constants/languageTabs'; This page documents metrics and configurations that drive the efficiency of your Worker fleet. @@ -247,9 +247,30 @@ These options define the maximum count of pollers performing poll requests on Wo #### SDK Examples +Select a concept to highlight the matching poller option: + [Go SDK docs](https://pkg.go.dev/go.temporal.io/sdk/worker#PollerBehaviorAutoscalingOptions) + ```go w := worker.New(c, "my-task-queue", worker.Options{ WorkflowTaskPollerBehavior: worker.NewPollerBehaviorAutoscaling(worker.PollerBehaviorAutoscalingOptions{}), @@ -257,9 +278,29 @@ w := worker.New(c, "my-task-queue", worker.Options{ NexusTaskPollerBehavior: worker.NewPollerBehaviorAutoscaling(worker.PollerBehaviorAutoscalingOptions{}), }) ``` + [Java SDK docs](https://javadoc.io/doc/io.temporal/temporal-sdk/latest/io/temporal/worker/tuning/PollerBehaviorAutoscaling.html) + ```java public class WorkerExample { public static void main(String[] args) { @@ -276,39 +317,99 @@ public class WorkerExample { } } ``` + [Python SDK docs](https://python.temporal.io/temporalio.worker.PollerBehaviorAutoscaling.html) + ```python worker = Worker( client, task_queue="my-task-queue", workflows=[MyWorkflow], activities=[my_activity], - + workflow_task_poller_behavior=PollerBehaviorAutoscaling(), activity_task_poller_behavior=PollerBehaviorAutoscaling(), nexus_task_poller_behavior=PollerBehaviorAutoscaling(), ) ``` + [TypeScript SDK docs](https://typescript.temporal.io/api/interfaces/proto.temporal.api.sdk.v1.WorkerConfig.IAutoscalingPollerBehavior) + ```ts const worker = await Worker.create({ connection, taskQueue: 'my-task-queue', workflowsPath: require.resolve('./workflows'), activities, - + workflowTaskPollerBehavior: PollerBehavior.autoscaling(), activityTaskPollerBehavior: PollerBehavior.autoscaling(), nexusTaskPollerBehavior: PollerBehavior.autoscaling(), }); ``` + [DotNet SDK docs](https://dotnet.temporal.io/api/Temporalio.Worker.Tuning.PollerBehavior.Autoscaling.html) + ```csharp using var worker = new TemporalWorker( client, @@ -322,23 +423,42 @@ using var worker = new TemporalWorker( .AddActivity(MyActivities.MyActivity) ); ``` + [Ruby SDK docs](https://ruby.temporal.io/Temporalio/Worker/PollerBehavior/Autoscaling.html) + ```ruby worker = Temporalio::Worker.new( client, 'my-task-queue', workflows: [MyWorkflow], activities: [MyActivity], - + workflow_task_poller_behavior: Temporalio::Worker::PollerBehavior::Autoscaling.new, activity_task_poller_behavior: Temporalio::Worker::PollerBehavior::Autoscaling.new, nexus_task_poller_behavior: Temporalio::Worker::PollerBehavior::Autoscaling.new, ) - ``` - + diff --git a/docs/production-deployment/worker-deployments/worker-versioning.mdx b/docs/production-deployment/worker-deployments/worker-versioning.mdx index 16b4ed5012..ab9fbb5518 100644 --- a/docs/production-deployment/worker-deployments/worker-versioning.mdx +++ b/docs/production-deployment/worker-deployments/worker-versioning.mdx @@ -18,7 +18,7 @@ tags: --- import { LANGUAGE_TAB_GROUP, getLanguageLabel } from '@site/src/constants/languageTabs'; -import { SdkTabs } from '@site/src/components'; +import { SdkTabs, AnnotatedCode } from '@site/src/components'; Worker Versioning is a Temporal feature that allows you to confidently deploy new changes to the Workflows running on your Workers without breaking them. Temporal enables this by helping you manage different builds or versions, formally @@ -147,25 +147,70 @@ three new parameters, with different names depending on the language: - (Optional) The [Default Versioning Behavior](#definition). If unset, you'll be required to specify the behavior on each Workflow. Or you can default to Pinned or Auto-Upgrade. -Follow the example for your SDK below: +Follow the example for your SDK below. Select a concept to highlight the matching lines: + ```go -buildID:= mustGetEnv("MY_BUILD_ID") +buildID := mustGetEnv("MY_BUILD_ID") w := worker.New(c, myTaskQueue, worker.Options{ DeploymentOptions: worker.DeploymentOptions{ UseVersioning: true, Version: worker.WorkerDeploymentVersion{ DeploymentName: "llm_srv", - BuildID: buildID, + BuildID: buildID, }, DefaultVersioningBehavior: workflow.VersioningBehaviorUnspecified, }, }) ``` + + ```java import io.temporal.worker.WorkerOptions; import io.temporal.common.VersioningBehavior; @@ -180,10 +225,32 @@ WorkerOptions.newBuilder() .setDefaultVersioningBehavior(VersioningBehavior.AUTO_UPGRADE) .build()) .build(); - ``` + + ```python from temporalio.common import WorkerDeploymentVersion, VersioningBehavior from temporalio.worker import Worker, WorkerDeploymentConfig @@ -202,10 +269,31 @@ Worker( ), ) ``` - + - + ```ts const myWorker = await Worker.create({ workflowsPath: require.resolve('./workflows'), @@ -217,22 +305,67 @@ const myWorker = await Worker.create({ connection: nativeConnection, }); ``` - + - + ```csharp var myWorker = new TemporalWorker( Client, new TemporalWorkerOptions(taskQueue) - {DeploymentOptions = new(new("llm_srv", "1.0"), true) - { DefaultVersioningBehavior = VersioningBehavior.Unspecified }, + { + DeploymentOptions = new(new("llm_srv", "1.0"), true) + { + DefaultVersioningBehavior = VersioningBehavior.Unspecified, + }, }.AddWorkflow()); ``` - + - + ```ruby worker = Temporalio::Worker.new( client: client, @@ -248,7 +381,7 @@ worker = Temporalio::Worker.new( ) ) ``` - + @@ -846,7 +979,7 @@ workflowOptions := client.StartWorkflowOptions{ VersioningOverride: &client.PinnedVersioningOverride{ Version: worker.WorkerDeploymentVersion{ DeploymentName: "DeployName", - BuildID: "1.0", + BuildID: "1.0", }, }, } diff --git a/scripts/mdx-to-md.mjs b/scripts/mdx-to-md.mjs index 0109e9478e..5e0a3da4dc 100644 --- a/scripts/mdx-to-md.mjs +++ b/scripts/mdx-to-md.mjs @@ -89,6 +89,7 @@ export const COMPONENT_REGISTRY = { ServerlessWorkerDemo: "strip-block", OperationsTable: "strip-block", InvitationContent: "strip-block", + AnnotatedCode: "strip-tag", // Details/summary (HTML, handled natively) details: "details", diff --git a/src/components/elements/AnnotatedCode/annotated-code.module.css b/src/components/elements/AnnotatedCode/annotated-code.module.css new file mode 100644 index 0000000000..7bce92c254 --- /dev/null +++ b/src/components/elements/AnnotatedCode/annotated-code.module.css @@ -0,0 +1,173 @@ +.root { + --ac-accent: var(--ifm-color-primary); + margin: 0 0 1rem; +} + +.hint { + font-size: 0.7rem; + font-weight: 600; + color: var(--ifm-color-emphasis-600); + text-transform: uppercase; + letter-spacing: 0.06em; + margin: 0 0 0.5rem; +} + +.pills { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin-bottom: 0.75rem; +} + +.pill { + --ac-pill: var(--ifm-color-emphasis-400); + padding: 0.35rem 0.85rem; + border: 1px solid color-mix(in srgb, var(--ac-pill) 55%, var(--ifm-color-emphasis-200)); + background: color-mix(in srgb, var(--ac-pill) 14%, var(--ifm-background-surface-color)); + color: var(--ifm-font-color-base); + font-size: 0.8rem; + font-weight: 400; + cursor: pointer; + transition: + border-color 0.12s ease, + background 0.12s ease, + color 0.12s ease, + box-shadow 0.12s ease; +} + +.pill:hover { + border-color: var(--ac-pill); + background: color-mix(in srgb, var(--ac-pill) 20%, transparent); + color: var(--ac-pill); +} + +.pillActive { + border-color: var(--ac-pill); + background: color-mix(in srgb, var(--ac-pill) 16%, transparent); + color: var(--ac-pill); + font-weight: 600; +} + +.description { + margin-bottom: 0.75rem; + padding: 0.75rem 1rem; + border: 1px solid color-mix(in srgb, var(--ac-pill) 40%, transparent); + background: color-mix(in srgb, var(--ac-pill) 10%, transparent); + box-shadow: inset 3px 0 0 var(--ac-pill); + font-size: 0.875rem; + line-height: 1.6; + color: var(--ifm-font-color-base); +} + +.codeWrap { + /* Background/color come from usePrismTheme (same as .theme-code-block) */ + box-shadow: var(--ifm-global-shadow-lw); + border-radius: var(--ifm-code-border-radius); + overflow: auto; + max-height: 32rem; +} + +.code { + margin: 0; + padding: 0.875rem 0; + font-size: 0.8rem; + font-family: var(--ifm-font-family-monospace); + line-height: 1.65; + color: inherit; + background: transparent; +} + +.line { + padding: 1px 1rem; + border-left: 3px solid transparent; + white-space: pre; + transition: opacity 0.12s ease, background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease; +} + +.lineActive { + border-left-color: var(--ac-accent); + background: color-mix(in srgb, var(--ac-accent) 22%, transparent); +} + +.lineDimmed { + opacity: 0.32; +} + +/* + * Light chrome: clear mid-tone Temporal colors (readable borders/labels). + * --ac-accent stays brand-bright for highlights on the dark code block. + */ +.toneIndigo { + --ac-pill: #5558e6; + --ac-accent: #444ce7; +} + +.toneMagenta { + --ac-pill: #9b4de0; + --ac-accent: #b664ff; +} + +.toneBlue { + --ac-pill: #2f7bc4; + --ac-accent: #3b82f6; +} + +.toneAmber { + --ac-pill: #c9840c; + --ac-accent: #f59e0b; +} + +:global(html[data-theme='dark']) .toneIndigo { + --ac-pill: #444ce7; + --ac-accent: #444ce7; +} + +:global(html[data-theme='dark']) .toneMagenta { + --ac-pill: #b664ff; + --ac-accent: #b664ff; +} + +:global(html[data-theme='dark']) .toneBlue { + --ac-pill: #3b82f6; + --ac-accent: #3b82f6; +} + +:global(html[data-theme='dark']) .toneAmber { + --ac-pill: #f59e0b; + --ac-accent: #f59e0b; +} + +:global(html[data-theme='dark']) .pill { + border-color: color-mix(in srgb, var(--ac-pill) 45%, transparent); + background: color-mix(in srgb, var(--ac-pill) 12%, transparent); + color: var(--ifm-font-color-base); +} + +:global(html[data-theme='dark']) .pill:hover { + border-color: var(--ac-pill); + background: color-mix(in srgb, var(--ac-pill) 20%, transparent); + box-shadow: 0 0 10px color-mix(in srgb, var(--ac-pill) 35%, transparent); +} + +:global(html[data-theme='dark']) .pillActive { + border-color: var(--ac-pill); + background: color-mix(in srgb, var(--ac-pill) 22%, transparent); + color: var(--ac-pill); + box-shadow: + 0 0 0 1px color-mix(in srgb, var(--ac-pill) 55%, transparent), + 0 0 18px color-mix(in srgb, var(--ac-pill) 55%, transparent); +} + +:global(html[data-theme='dark']) .description { + border-color: color-mix(in srgb, var(--ac-accent) 55%, transparent); + background: color-mix(in srgb, var(--ac-accent) 14%, transparent); + box-shadow: + inset 3px 0 0 var(--ac-accent), + 0 0 20px color-mix(in srgb, var(--ac-accent) 18%, transparent); +} + +:global(html[data-theme='dark']) .lineActive { + border-left-color: var(--ac-accent); + background: color-mix(in srgb, var(--ac-accent) 22%, transparent); + box-shadow: inset 0 0 24px color-mix(in srgb, var(--ac-accent) 35%, transparent); +} diff --git a/src/components/elements/AnnotatedCode/index.js b/src/components/elements/AnnotatedCode/index.js new file mode 100644 index 0000000000..116e82ae5a --- /dev/null +++ b/src/components/elements/AnnotatedCode/index.js @@ -0,0 +1,133 @@ +import React, { useMemo, useState } from 'react'; +import { usePrismTheme } from '@docusaurus/theme-common'; +import styles from './annotated-code.module.css'; + +const TONES = ['indigo', 'magenta', 'blue', 'amber']; + +const TONE_CLASS = { + indigo: styles.toneIndigo, + magenta: styles.toneMagenta, + blue: styles.toneBlue, + amber: styles.toneAmber, +}; + +function resolveTone(annotation, index) { + const requested = annotation?.color; + if (requested && TONE_CLASS[requested]) return requested; + return TONES[index % TONES.length]; +} + +/** Pull plain text out of MDX/Docusaurus code-block children. */ +function extractText(node) { + if (node == null || typeof node === 'boolean') return ''; + if (typeof node === 'string' || typeof node === 'number') return String(node); + if (Array.isArray(node)) return node.map(extractText).join(''); + if (React.isValidElement(node)) return extractText(node.props.children); + return ''; +} + +/** + * Highlightable code block. Put a normal Markdown fence as children so the + * sample stays in the MDX (and in LLM markdown via strip-tag). + * + * @param {object} props + * @param {{ label: string, description: string, lines: number[], color?: 'indigo'|'magenta'|'blue'|'amber' }[]} props.annotations + * @param {string} [props.hint='Highlight a concept'] + * @param {React.ReactNode} props.children - Markdown code fence + */ +export default function AnnotatedCode({ + annotations = [], + hint = 'Highlight a concept', + children, +}) { + const prismTheme = usePrismTheme(); + const [activeIndex, setActiveIndex] = useState(null); + + const code = useMemo(() => { + const raw = extractText(children); + return raw.replace(/^\n/, '').replace(/\n$/, ''); + }, [children]); + + const lines = code ? code.split('\n') : []; + const active = activeIndex !== null ? annotations[activeIndex] : null; + const activeTone = + activeIndex !== null ? resolveTone(annotations[activeIndex], activeIndex) : null; + const activeToneClass = activeTone ? TONE_CLASS[activeTone] : ''; + const activeLines = new Set(active?.lines ?? []); + const hasActive = activeLines.size > 0; + + const codeSurfaceStyle = { + backgroundColor: prismTheme.plain.backgroundColor, + color: prismTheme.plain.color, + }; + + function toggle(i) { + setActiveIndex((prev) => (prev === i ? null : i)); + } + + // If we couldn't extract fence text, fall back to rendering children as-is. + if (!code) { + return
{children}
; + } + + return ( +
+ {annotations.length > 0 && ( + <> +
{hint}
+
+ {annotations.map((annotation, i) => { + const isActive = activeIndex === i; + const tone = resolveTone(annotation, i); + return ( + + ); + })} +
+ {active && ( +
+ {active.description} +
+ )} + + )} + +
+
+          {lines.map((line, i) => {
+            const lineNum = i + 1;
+            const isActive = activeLines.has(lineNum);
+            return (
+              
+ {line || ' '} +
+ ); + })} +
+
+
+ ); +} diff --git a/src/components/elements/index.js b/src/components/elements/index.js index 921cf64885..a987d32046 100644 --- a/src/components/elements/index.js +++ b/src/components/elements/index.js @@ -4,4 +4,5 @@ export * from './Tile' export * from './Images' export * from './RelatedRead' export * from './ReleaseNoteHeader' -export * from './Sdk' \ No newline at end of file +export * from './Sdk' +export { default as AnnotatedCode } from './AnnotatedCode' \ No newline at end of file