Frontend Development

Motivation

The frontend development for AutoFlow is responsible for providing a user-friendly interface for managing and monitoring the AutoFlow system. The frontend is built using React and provides a range of functionalities, including:

  • Dashboard: Displays key metrics and insights about the AutoFlow system.
  • Task Management: Enables users to create, manage, and monitor tasks.
  • Cluster Management: Provides tools for managing and monitoring the AutoFlow cluster.
  • Workflow Configuration: Allows users to define and configure workflows.
  • Alert Management: Provides tools for configuring and managing alerts.

Sub-Topics

  • Codebase Structure: The frontend codebase is organized into multiple modules, each responsible for a specific functionality.
  • Component Library: AutoFlow uses a custom component library built with React to ensure consistency and reusability.
  • Data Fetching: Data is fetched from the backend API using the axios library.
  • State Management: The Redux library is used for managing the application’s state.
  • Styling: The frontend uses a combination of CSS and Styled-components to style the UI.
  • Testing: Jest is used for unit testing, while Cypress is used for end-to-end testing.

Codebase Structure

The frontend codebase is organized into the following folders:

  • src: Contains all the source code for the frontend application.
  • public: Contains static assets such as images and HTML files.
  • package.json: Defines the project dependencies and scripts.

src:

  • components: Contains reusable UI components.
  • containers: Contains components that connect to the Redux store.
  • pages: Contains the application’s routes and views.
  • services: Contains utility functions for fetching data from the backend API.
  • store: Contains the Redux store and reducers.
  • utils: Contains utility functions for various tasks.

Component Library

AutoFlow uses a custom component library built with React to ensure consistency and reusability. The component library provides a set of pre-built components that can be used throughout the application.

Example:

import { Button, Card, Icon } from 'autoflow-ui';
          

This code imports the Button, Card, and Icon components from the autoflow-ui component library.

Data Fetching

Data is fetched from the backend API using the axios library. The axios library provides a simple and easy-to-use API for making HTTP requests.

Example:

import axios from 'axios';
          
          const fetchData = async () => {
            const response = await axios.get('/api/tasks');
            return response.data;
          };
          

This code fetches data from the /api/tasks endpoint using the axios.get method.

State Management

The Redux library is used for managing the application’s state. Redux provides a centralized store for managing state and a set of tools for updating and accessing the state.

Example:

// actions.js
          
          export const FETCH_TASKS_REQUEST = 'FETCH_TASKS_REQUEST';
          export const FETCH_TASKS_SUCCESS = 'FETCH_TASKS_SUCCESS';
          export const FETCH_TASKS_FAILURE = 'FETCH_TASKS_FAILURE';
          
          export const fetchTasks = () => ({
            type: FETCH_TASKS_REQUEST,
          });
          
          export const fetchTasksSuccess = (tasks) => ({
            type: FETCH_TASKS_SUCCESS,
            payload: tasks,
          });
          
          export const fetchTasksFailure = (error) => ({
            type: FETCH_TASKS_FAILURE,
            payload: error,
          });
          
          // reducers.js
          
          const initialState = {
            tasks: [],
            isLoading: false,
            error: null,
          };
          
          export default function tasksReducer(state = initialState, action) {
            switch (action.type) {
              case FETCH_TASKS_REQUEST:
                return {
                  ...state,
                  isLoading: true,
                };
              case FETCH_TASKS_SUCCESS:
                return {
                  ...state,
                  tasks: action.payload,
                  isLoading: false,
                };
              case FETCH_TASKS_FAILURE:
                return {
                  ...state,
                  error: action.payload,
                  isLoading: false,
                };
              default:
                return state;
            }
          }
          
          // components/TaskList.js
          
          import React from 'react';
          import { useSelector, useDispatch } from 'react-redux';
          import { fetchTasks } from '../store/actions';
          
          const TaskList = () => {
            const tasks = useSelector((state) => state.tasks.tasks);
            const isLoading = useSelector((state) => state.tasks.isLoading);
            const error = useSelector((state) => state.tasks.error);
            const dispatch = useDispatch();
          
            useEffect(() => {
              dispatch(fetchTasks());
            }, []);
          
            if (isLoading) {
              return <p>Loading tasks...</p>;
            }
          
            if (error) {
              return <p>Error loading tasks: {error.message}</p>;
            }
          
            return (
              <ul>
                {tasks.map((task) => (
                  <li key={task.id}>{task.name}</li>
                ))}
              </ul>
            );
          };
          
          export default TaskList;
          

This code demonstrates how to use Redux to manage the state of the tasks array. The fetchTasks action creator is dispatched to fetch data from the backend API, and the tasksReducer updates the state based on the action. The TaskList component uses the useSelector hook to access the state and the useDispatch hook to dispatch actions.

Styling

The frontend uses a combination of CSS and Styled-components to style the UI. Styled-components allow for writing CSS directly within JavaScript components, making it easier to style components and maintain consistency.

Example:

import styled from 'styled-components';
          
          const Container = styled.div`
            display: flex;
            flex-direction: column;
            align-items: center;
            padding: 20px;
          `;
          
          const Title = styled.h1`
            font-size: 24px;
            font-weight: bold;
            margin-bottom: 10px;
          `;
          
          const Button = styled.button`
            background-color: #4CAF50;
            color: white;
            padding: 10px 20px;
            border: none;
            cursor: pointer;
          `;
          
          const MyComponent = () => {
            return (
              <Container>
                <Title>Welcome to AutoFlow</Title>
                <Button>Get Started</Button>
              </Container>
            );
          };
          
          export default MyComponent;
          

This code demonstrates how to use styled-components to style a simple component. The Container, Title, and Button components are styled using styled-components.

Testing

Jest is used for unit testing, while Cypress is used for end-to-end testing. Jest provides a powerful testing framework for JavaScript, while Cypress is a browser-based end-to-end testing framework.

Example:

// src/components/Button.test.js
          
          import React from 'react';
          import { render, screen } from '@testing-library/react';
          import Button from './Button';
          
          describe('Button', () => {
            it('renders correctly', () => {
              render(<Button>Click Me</Button>);
              expect(screen.getByText('Click Me')).toBeInTheDocument();
            });
          });
          

This code demonstrates how to write a unit test for the Button component using Jest. The test renders the component and then asserts that the text “Click Me” is present in the rendered output.

Example:

// cypress/integration/tasks.spec.js
          
          describe('Tasks Page', () => {
            it('should display the task list', () => {
              cy.visit('/tasks');
          
              cy.get('ul[data-testid="task-list"]').should('be.visible');
              cy.get('li[data-testid="task-item"]').should('have.length.greaterThan(0)');
            });
          });
          

This code demonstrates how to write an end-to-end test for the Tasks page using Cypress. The test visits the /tasks route and then asserts that the task list is visible and contains at least one task item.

Conclusion

This outline provides a high-level overview of the frontend development for AutoFlow. For more details, refer to the source code and documentation available in the project repository.