| 
 | 1 | +// index.tsx  | 
 | 2 | + | 
1 | 3 | import React, { useEffect, useState } from 'react';  | 
2 |  | -import Tabs from '@theme/Tabs';  | 
3 |  | -import TabItem from '@theme/TabItem';  | 
4 | 4 | import CodeBlock from '@theme/CodeBlock';  | 
 | 5 | +import Note from '@site/src/components/Note';  | 
5 | 6 | import Steps from '@site/src/components/Steps';  | 
 | 7 | +import TabItem from '@theme/TabItem';  | 
 | 8 | +import Tabs from '@theme/Tabs';  | 
6 | 9 | 
 
  | 
7 |  | -import * as yaml from 'js-yaml';  | 
8 |  | - | 
9 |  | -// Define constants for the base URL and workflows directory path  | 
10 |  | -const CLOUDPOSSE_DOCS_URL = 'https://raw.githubusercontent.com/cloudposse/docs/master/';  | 
11 |  | -const WORKFLOWS_DIRECTORY_PATH = 'examples/snippets/stacks/workflows/';  | 
12 |  | - | 
13 |  | -async function GetAtmosTerraformCommands(workflow: string, fileName: string, stack?: string): Promise<string[] | undefined> {  | 
14 |  | -  try {  | 
15 |  | -    // Construct the full URL to the workflow YAML file  | 
16 |  | -    const url = `${CLOUDPOSSE_DOCS_URL}${WORKFLOWS_DIRECTORY_PATH}${fileName}.yaml`;  | 
17 |  | - | 
18 |  | -    // Fetch the workflow file from the constructed URL  | 
19 |  | -    const response = await fetch(url);  | 
20 |  | -    if (!response.ok) {  | 
21 |  | -      console.error('Failed to fetch the file:', response.statusText);  | 
22 |  | -      console.error('Workflow URL:', url);  | 
23 |  | -      return undefined;  | 
24 |  | -    }  | 
25 |  | -    const fileContent = await response.text();  | 
26 |  | - | 
27 |  | -    // Parse the YAML content  | 
28 |  | -    const workflows = yaml.load(fileContent) as any;  | 
29 |  | - | 
30 |  | -    // Find the specified workflow in the parsed YAML  | 
31 |  | -    if (workflows && workflows.workflows && workflows.workflows[workflow]) {  | 
32 |  | -      const workflowDetails = workflows.workflows[workflow];  | 
33 |  | - | 
34 |  | -      // Extract the commands under that workflow  | 
35 |  | -      const commands = workflowDetails.steps.map((step: any) => {  | 
36 |  | -        let command = step.command;  | 
37 |  | -        // TODO handle nested Atmos Workflows  | 
38 |  | -        // For example: https://raw.githubusercontent.com/cloudposse/docs/master/examples/snippets/stacks/workflows/identity.yaml  | 
39 |  | -        if (!step.type) {  | 
40 |  | -          command = `atmos ${command}`;  | 
41 |  | -          if (stack) {  | 
42 |  | -            command += ` -s ${stack}`;  | 
43 |  | -          }  | 
44 |  | -        }  | 
45 |  | -        return command;  | 
46 |  | -      });  | 
47 |  | - | 
48 |  | -      return commands;  | 
49 |  | -    }  | 
 | 10 | +import { GetAtmosTerraformCommands } from './utils';  | 
 | 11 | +import { WorkflowStep, WorkflowData } from './types';  | 
 | 12 | +import { WORKFLOWS_DIRECTORY_PATH } from './constants';  | 
50 | 13 | 
 
  | 
51 |  | -    // Return undefined if the workflow is not found  | 
52 |  | -    return undefined;  | 
53 |  | -  } catch (error) {  | 
54 |  | -    console.error('Error fetching or parsing the file:', error);  | 
55 |  | -    return undefined;  | 
56 |  | -  }  | 
 | 14 | +interface AtmosWorkflowProps {  | 
 | 15 | +  workflow: string;  | 
 | 16 | +  stack?: string;  | 
 | 17 | +  fileName: string;  | 
57 | 18 | }  | 
58 | 19 | 
 
  | 
59 |  | -export default function AtmosWorkflow({ workflow, stack = "", fileName }) {  | 
60 |  | -  const [commands, setCommands] = useState<string[]>([]);  | 
 | 20 | +export default function AtmosWorkflow({ workflow, stack = '', fileName }: AtmosWorkflowProps) {  | 
 | 21 | +  const [workflowData, setWorkflowData] = useState<WorkflowData | null>(null);  | 
61 | 22 |   const fullFilePath = `${WORKFLOWS_DIRECTORY_PATH}${fileName}.yaml`;  | 
62 | 23 | 
 
  | 
63 | 24 |   useEffect(() => {  | 
64 |  | -    GetAtmosTerraformCommands(workflow, fileName, stack).then((cmds) => {  | 
65 |  | -      if (Array.isArray(cmds)) {  | 
66 |  | -        setCommands(cmds);  | 
 | 25 | +    GetAtmosTerraformCommands(workflow, fileName, stack).then((data) => {  | 
 | 26 | +      if (data) {  | 
 | 27 | +        setWorkflowData(data);  | 
67 | 28 |       } else {  | 
68 |  | -        setCommands([]); // Default to an empty array if cmds is undefined or not an array  | 
 | 29 | +        setWorkflowData(null);  | 
69 | 30 |       }  | 
70 | 31 |     });  | 
71 | 32 |   }, [workflow, fileName, stack]);  | 
72 | 33 | 
 
  | 
73 | 34 |   return (  | 
74 | 35 |     <Tabs queryString="workflows">  | 
75 | 36 |       <TabItem value="commands" label="Commands">  | 
76 |  | -        These are the commands included in the <code>{workflow}</code> workflow in the <code>{fullFilePath}</code> file:  | 
 | 37 | +        <Note title={workflow}>  | 
 | 38 | +          These are the commands included in the <code>{workflow}</code> workflow in the{' '}  | 
 | 39 | +          <code>{fullFilePath}</code> file:  | 
 | 40 | +        </Note>  | 
 | 41 | +        {workflowData?.description && (  | 
 | 42 | +          <p className=".workflow-title">  | 
 | 43 | +            {workflowData.description}  | 
 | 44 | +          </p>  | 
 | 45 | +        )}  | 
77 | 46 |         <Steps>  | 
78 | 47 |           <ul>  | 
79 |  | -            {commands.length > 0 ? commands.map((cmd, index) => (  | 
80 |  | -              <li key={index}>  | 
81 |  | -                <CodeBlock language="bash">  | 
82 |  | -                  {cmd}  | 
83 |  | -                </CodeBlock>  | 
84 |  | -              </li>  | 
85 |  | -            )) : 'No commands found'}  | 
 | 48 | +            {workflowData?.steps.length ? (  | 
 | 49 | +              workflowData.steps.map((step, index) => (  | 
 | 50 | +                <li key={index}>  | 
 | 51 | +                  {step.type === 'title' ? (  | 
 | 52 | +                    <>  | 
 | 53 | +                      <h4 className=".workflow-title">  | 
 | 54 | +                        {step.content.split('\n\n')[0]}  | 
 | 55 | +                      </h4>  | 
 | 56 | +                      <CodeBlock language="bash">  | 
 | 57 | +                        {step.content.split('\n\n')[1]}  | 
 | 58 | +                      </CodeBlock>  | 
 | 59 | +                    </>  | 
 | 60 | +                  ) : (  | 
 | 61 | +                    <CodeBlock language="bash">{step.content}</CodeBlock>  | 
 | 62 | +                  )}  | 
 | 63 | +                </li>  | 
 | 64 | +              ))  | 
 | 65 | +            ) : (  | 
 | 66 | +              'No commands found'  | 
 | 67 | +            )}  | 
86 | 68 |           </ul>  | 
87 | 69 |         </Steps>  | 
88 |  | -        Too many commands? Consider using the Atmos workflow! 🚀  | 
 | 70 | +        <p>Too many commands? Consider using the Atmos workflow! 🚀</p>  | 
89 | 71 |       </TabItem>  | 
90 | 72 |       <TabItem value="atmos" label="Atmos Workflow">  | 
91 |  | -        Run the following from your Geodesic shell using the Atmos workflow:  | 
 | 73 | +        <p>Run the following from your Geodesic shell using the Atmos workflow:</p>  | 
92 | 74 |         <CodeBlock language="bash">  | 
93 |  | -          atmos workflow {workflow} -f {fileName} {stack && `-s ${stack}`}  | 
 | 75 | +          {`atmos workflow ${workflow} -f ${fileName} ${stack ? `-s ${stack}` : ''}`}  | 
94 | 76 |         </CodeBlock>  | 
95 | 77 |       </TabItem>  | 
96 | 78 |     </Tabs>  | 
 | 
0 commit comments