Skip to content

Frontend Docs need Updated #166

Closed
campb303 opened this issue Jan 21, 2021 · 15 comments
Closed

Frontend Docs need Updated #166

campb303 opened this issue Jan 21, 2021 · 15 comments
Assignees
Labels
documentation Related to the writing documentation or the tools used to generate docs high-priority Needs immediate extra focus question Something that requires more information before moving forward
Projects

Comments

@campb303
Copy link
Collaborator

Some components have out of date docs. Other components have no docs. These need to be updated.

@campb303 campb303 added documentation Related to the writing documentation or the tools used to generate docs frontend high-priority Needs immediate extra focus labels Jan 21, 2021
@campb303 campb303 added this to the v1-readonly milestone Jan 21, 2021
@wrigh393
Copy link
Collaborator

wrigh393 commented Feb 8, 2021

As of today most of the docs have been updated. The only doc that still needs to be updated is ItemBodyView. The doc for this component gives an error related to the theme palette that we created. Once this issue is addressed all the docs will be updated.

@wrigh393 wrigh393 linked a pull request Feb 10, 2021 that will close this issue
@campb303
Copy link
Collaborator Author

react-stylguidist does not support context managers therefore AuthProvider and other context dependent components cannot be used in the docs. These components can still be documented though.

@campb303
Copy link
Collaborator Author

A lack of support for context managers in react-styleguidist and our new dependency on context for Auth and Item management means we cannot document some of our components using this system. We need to look into alternatives.

@campb303 campb303 added the question Something that requires more information before moving forward label Feb 23, 2021
@wrigh393
Copy link
Collaborator

Storybook seems to be a solid alternative to react-styleguidist that would allow us to use context managers in our documentation. Storybook includes these features:

  • documention of components
  • The ability to test component visually in the docs
  • Provides add-ons that offer additional features that may help us in the future

It also supports the use of context providers through mocking components. I will update the issue with a more in-depth look at how this works and how it can be used for our project.

@wrigh393
Copy link
Collaborator

As mentioned in my previous comment, Storybook seems like a good alternative to react-stylguidist due to its large feature set and its ability to work with context providers. I will give an overview of the features that are available with Storybook.

Documentation

Storybook offers a variety of ways to document components. Storybook provides by default what they call a DocsPage which requires no configuration and combines all text descriptions, docgen comments, args tables, and code examples into a single page for each component. There is also the option to override the DocsPage with a variety of options:

  • null to remove docs
  • MDX docs
  • A custom component

Currently, all of the documentation for the frontend is written using MD so migrating to MDX and Storybook should be a simple process due to the syntax being similar and its ability to have JSX component blocks in the file.

Testing

Storybook offers us the ability to work with components individually and save different states as stories. These stories allow us to see each state of the component. Storybook offers these testing methods:

  • Manual Testing
  • Unit testing
    • Unit testing is good for testing the functional parts of a component. They use a fixed input to check that a component returns the expected value
  • Visual regression testing
    • These work by taking a screenshot of a story and comparing those images commit -to-commit so that changes can be easily identified. These are good for things that a user sees such as color, size, etc.
    • Storybook uses Chromatic which they maintain themselves but also offer StoryShots which is an addon that integrates with jest-image-snapshot
  • Interaction testing
    • Using the interaction tools like Enzyme and Cypress we can test components and their outputs for expected user interactions
  • Snapshot testing
    • These tests compare the markup for a components story with defined baselines so that we can find changes in the code that cause rendering errors and warnings.

Overall, the testing abilities of Storybook seem useful as we have also been looking into ways to test front end changes as stated in #22

Add-ons

Add-ons allow Storybook to have additional features that are not present in the core build. Most features are implemented as add-ons. There are useful add-ons that allow us to test things like accessibility and responsive design as well as giving us the ability to use our own Context providers.


Conclusion

Storybook seems to be a powerful tool that will allow us to not only document our components but also offers solid options for implementing frontend testing which is an important aspect of the project that needs to be added.

@wrigh393
Copy link
Collaborator

For clarification here is the definition of a "story" as defined by Storybook:

A story captures the rendered state of a UI component. Developers write multiple stories per component that describe all the “interesting” states a component can support.

Essential a story is the different states that a component can be presented in as well as the props or args as they are referred to by Storybook that allows the components to be dynamically altered to see how different changes impact the component.

@wrigh393
Copy link
Collaborator

wrigh393 commented Mar 1, 2021

Here is an example of how Storybook docs look and how to write a story.

Set up

To install Storybook their docs run this command:

#Add Storybook
npx sb init

This will install the Storybook CLI. This command is not made for empty projects as it uses you existing project to determine how to setup Storybook for the project.

Once installed, run this command to start Storybook:

# Starts Storybook in development mode
npm run storybook

This will open Storybook on localhost:6006. Here you will find the Storybook welcome screen that has some useful items such as:

  • Useful links for more in-depth configuration of Storybook
  • Link to learn more about Storybook
  • A few example docs

Storybook comes with two CLI utilities start-storybook and build-storybook each with their own commands that can be found here

Naming the Documentation

In order to write docs with Storybook all documentation files should be named using the following naming convention:

YourComponent.stories.mdx OR YourComponent.stories.js

Our current documentation is written in Markdown so it makes the most sense for us to use MDX which allows us to write JSX straight into Markdown documents. In this example I will use the ItemTable component so the docs should be named ItemTable.stories.mdx

To write the story we need to add a few import statements to our MDX file

import { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';
import  ItemTable  from './ItemTable';
  • The Meta component is used to name our docs in the Storybook sidebar
  • The Story component is where our component will be rendered
  • The Canvas component allows interaction with the component and provides Code snippets for the component

As stated above, the Meta component is used to define the name of the documentation as well as what component the docs are referring to. Here is an example using ItemTable

<Meta title="ItemTable" component={ItemTable} />

Getting the props of the component

To get the props of the component being documented we need to export the component as a const that we will use to expand the props so that we can access them for the examples in the story.

export const Template = (props) => <ItemTable {...props} />

Adding a story

To reiterate, stories are examples of the different states of a component. In this example for ItemTable I will use two states: Loading and Loaded:

Loading

<Canvas>
  <Story name="Loading" args={{
  data: [],
	rowCanBeSelected:false,
	loading:true,
    }}>
    {Template.bind({})}
   </Story>
  </Canvas>

Loaded

<Canvas>
  <Story name="Loaded" args={{
  data: [
  {"queue": "ce", "number": 9, "lastUpdated": "09-11-20 12:14 PM", "isLocked": false, "userEmail": "lslusher@purdue.edu", "userName": "Slusher, Laura M", "userAlias": "lslusher", "assignedTo": "bekuma", "subject": "RE: New laptop", "status": "waiting on reply/time to call", "priority": "deploy", "department": "che", "building": "frny", "dateReceived": "2020-03-12T18:07:27+0000"},
  {"queue": "ce", "number": 42, "lastUpdated": "09-11-20 12:14 PM", "isLocked": false, "userEmail": "feng293@purdue.edu", "userName": "", "userAlias": "feng293", "assignedTo": "schmid22", "subject": "Upgrade system and Abaqus", "status": "", "priority": "", "department": "", "building": "", "dateReceived": "2020-05-14T10:21:32-0400"},
  {"queue": "ce", "number": 51, "lastUpdated": "09-11-20 12:14 PM", "isLocked": false, "userEmail": "jclauso@purdue.edu", "userName": "", "userAlias": "jclauso", "assignedTo": "schmid22", "subject": "ECN privileges for future grad student", "status": "Waiting for reply", "priority": "", "department": "", "building": "", "dateReceived": "2020-05-14T15:03:07-0400"}
  ],
	rowCanBeSelected:false,
	loading:false,
    }}>
    {Template.bind({})}
   </Story>
    </Canvas>

In this example first, we wrapped the Story component in the Canvas component so that we could get a code snippet of the component that story is for. Then in the Story component, we have a few important props.

  • The name prop is used to name the story. In this case, the story is for the loading state of the ItemTable so name was set to "Loading"
  • The args prop is where we access the props of our component. ItemTable has three props: data, rowCanBeSelected, and loading. Here those props are set to the values that they would have if the component was in the loading state.

Template.bind({}) is uses the bind() method to create a copy of our function. This so each story can have its own set of props.

Here is the full code for the ItemTable docs using Storybook and what it looks like

import { Meta, Story, Canvas } from '@storybook/addon-docs/blocks';
import  ItemTable  from './ItemTable';

The ItemTable is the primary view for webqueue2. It displays item metadata for items of selected queues and allows for filtering by field and opening an item by clicking. Items are passed in as a required parameter. It is to be used with the [ItemTableAppBar](/#/Components/ItemTableAppBar).
It is based on [react-table](https://react-table.tanstack.com/).

<Meta title="ItemTable" component={ItemTable} />

export const Template = (props) => <ItemTable {...props} />

# ItemTable With Content

<Canvas>
  <Story name="Loaded" args={{
  data: [
  {"queue": "ce", "number": 9, "lastUpdated": "09-11-20 12:14 PM", "isLocked": false, "userEmail": "lslusher@purdue.edu", "userName": "Slusher, Laura M", "userAlias": "lslusher", "assignedTo": "bekuma", "subject": "RE: New laptop", "status": "waiting on reply/time to call", "priority": "deploy", "department": "che", "building": "frny", "dateReceived": "2020-03-12T18:07:27+0000"},
  {"queue": "ce", "number": 42, "lastUpdated": "09-11-20 12:14 PM", "isLocked": false, "userEmail": "feng293@purdue.edu", "userName": "", "userAlias": "feng293", "assignedTo": "schmid22", "subject": "Upgrade system and Abaqus", "status": "", "priority": "", "department": "", "building": "", "dateReceived": "2020-05-14T10:21:32-0400"},
  {"queue": "ce", "number": 51, "lastUpdated": "09-11-20 12:14 PM", "isLocked": false, "userEmail": "jclauso@purdue.edu", "userName": "", "userAlias": "jclauso", "assignedTo": "schmid22", "subject": "ECN privileges for future grad student", "status": "Waiting for reply", "priority": "", "department": "", "building": "", "dateReceived": "2020-05-14T15:03:07-0400"}
  ],
	rowCanBeSelected:false,
	loading:false,
    }}>
    {Template.bind({})}
   </Story>
    </Canvas>

   # ItemTable Loading Content

<Canvas>
  <Story name="Loading" args={{
  data: [],
	rowCanBeSelected:false,
	loading:true,
    }}>
    {Template.bind({})}
   </Story>
  </Canvas>

image

Canvas

The Canvas view in Storybook allows for interaction with the component in real-time, allowing users to see how changes to the props impact the component.

Canvas View
image

Here is an example of interacting with the component in the canvas view:

Animated GIF-downsized_large

@wrigh393
Copy link
Collaborator

wrigh393 commented Mar 3, 2021

Implementing the docs using Storybook for ItemView has been difficult. I'm having trouble getting the context to be passed to the component so that it will render the data from the item. I think part of the issue is that the ItemView component is not actually passed any props but further testing is needed. I believe this portion of the docs is similar to what we want to accomplish but I haven't been successful in implementing it.

@campb303 campb303 added this to To do in v1.0 Mar 8, 2021
@wrigh393
Copy link
Collaborator

All of the docs have been migrated from react-styleguidist to Storybook. Some docs may still need to be worked on depending on if they function properly after the changes to how we load items in the table (#8)

@wrigh393
Copy link
Collaborator

Currently, the docs don't display how components look when the dark mode color palette, which is important not only so that people that look at our documentation can see how the two versions of the component differ but also so that we can see how these changes affect component if we decide to use Storybook for testing docs as well. I'm still testing to see if there is a way to accomplish this without using any more Storybook addons. If its not possible there is a Storybook addon called storybook-dark-mode that seems like it would be easy enough to implement.

@wrigh393
Copy link
Collaborator

Storybook offers the ability to add icons to the toolbar so that users can interact with the canvas using the toolbar. In our case, we would want users to be able to set the theme palette for a component based on the value that the select with the toolbar button. The problem that I'm facing right now is that based on my understanding of the documentation here only string values can be used for the toolbar button values.

This is a problem because of how we define whether the dark mode theme should be the active theme. Our theme is determined based on a boolean. I have tried to use a state variable to set the theme based on which string value is selected with the toolbar icon but that hasn't worked,

I think another viable course of action may be to just create a story for the dark mode variant of our components. Based on the docs here we should be able to define a decorator that passes the theme for individual stories in a similar way that we are passing it globally.

@wrigh393
Copy link
Collaborator

A Dark mode selector has been added to the toolbar of the Storybook docs. Below you will find a screenshot that shows where that icon is.
webqueue2_Storybook_Toolbar_Screenshot

The problem at hand now is that some components don't display properly when in Dark mode. These components are:

  • Item HeaderView
  • ItemTable
  • ItemTableFilter
  • QueueSelector

Most of these components are apart of larger components where they are rendered properly, but on their own, they don't.

@campb303 campb303 moved this from To do to In progress in v1.0 Mar 29, 2021
@wrigh393
Copy link
Collaborator

wrigh393 commented Apr 7, 2021

Here is an explanation of how the dark mode toggle was added to the toolbar.

Globals

Globals in Storybook represent non-story-specific inputs to the rendering of the story. These inputs aren't passed to the story arguments but can be accessed as context.globals. these globals are typically used with decorators, which are applied to all stories. The way this works is when the global value changed the story re-renders and the decorators run with the new value. Ti suggested that the easiest way to change globals is by creating a toolbar action for them.

Creating a toolbar action

To create a toolbar action in the storybook/preview.js you can add a globalTypes with a toolbar annotation. I will use the code from our implementation of a dark mode toolbar action as an example.

export const globalTypes = {
//This is the name of the global.  To reference this in stories you would use context.globals.theme
  theme: {
//The name of the toolbar action
    name: 'Set Dark Mode',
//The description of the toolbar action.  
//This is displayed when the icon is being hovered over.
    description: 'Global theme for components',
//The default value of the global.
    defaultValue: false,
//This lets Storybook know that you are creating a toolbar action.
    toolbar: {
      //Defines the  icon  that is displayed in the toolbar
      icon: 'mirror',
//An array of items that can be selected from the dropdown when the toolbar action is selected.
      items: [
//Value is what the global's value will be set to.  
//The title is what will show in the dropdown menu.  
//The icon is what icon will display when that item is selected.
        { value: true, title: "Dark Mode active", icon: "contrast" },
        { value: false, title: "Dark Mode off", icon: "switchalt" }
      ],
    },
  },
};

Creating a decorator

Now that our global is defined we can use it with a decorator to change how our stories are rendered based on the value of the global. In the storybook/preview.js config you can define a decorator to consume that value. In our case we are using the global value in conjunction with our ThemeProvider from Material-UI to toggle dark mode. Below is an example from our code.

const withThemeProvider = (Story, context) => {
//Here the them is set to our webqueueTheme which acceprs
  const theme = webqueueTheme(context.globals.theme);
  return (
    <ThemeProvider theme={theme} >
      <Story {...context} />
    </ThemeProvider>
  )
}

You can then add this decorator to the array of decorators. Here is the example from our code.

export const decorators = [
  (Story) => (
    <ItemProvider>
      <Story />
    </ItemProvider>
  ),
  withThemeProvider
];

With that, we have defined a global, gave it an action/icon in the toolbar, passed its value to be used in a decorator, and applied that decorator to all of our stories. Globals can also be passed to stories and addons by referencing the value of the global. In our case, this would be referenced by using context.globals.theme. It is recommended to consume globals from a decorator but it is good to know that functionality is available to us.

@campb303
Copy link
Collaborator Author

campb303 commented Apr 9, 2021

Working on this.

@campb303
Copy link
Collaborator Author

Docs have been updated. Styleguidist integrations were removed. Storybook was integrated. Some cleaning was also done to remove stale files.

Sign in to join this conversation on GitHub.
Labels
documentation Related to the writing documentation or the tools used to generate docs high-priority Needs immediate extra focus question Something that requires more information before moving forward
Projects
No open projects
v1.0
  
In progress
Development

Successfully merging a pull request may close this issue.

2 participants