Skip to content

Conversation

@zchsh
Copy link
Contributor

@zchsh zchsh commented Feb 17, 2021

🎟️ Asana Task
πŸ” Preview Link


This PR refactors DocsSidenav to implement the related RFC, MKTG-032.

This change also bleeds into DocsPage, which has a significant refactor to align with the updated DocsSidenav API, and GlossaryPage, which is a less drastic but still breaking refactor to align with `DocsPage.

I've proven out these changes in hashicorp/packer#10656 and more recently hashicorp/packer#10716, so apart from unit tests, we have those PRs as examples of the refactored components working "in the wild". We could open further PRs on other docs sites to confirm the GlossaryPage compatibility, or rather the upgrade path.

Release Information

Please select one (required)

  • Major (This PR introduces a breaking (incompatible API) change)
  • Minor (This PR adds functionality but it backwards-compatible)
  • Patch (This PR adds a backwards-compatible bug fix)
Release Notes (required) This release refactors `docs-sidenav`, `docs-page`, and `glossary-page` to implement [the MKTG-032 RFC](https://docs.google.com/document/d/1FPyWid2NmNI9E_6lH2UIMuEPqjqDCGe3F8wraPRQHQ8/edit#).

PR Checklist πŸš€

Items in this checklist may not may not apply to your PR, but please consider each item carefully.

  • Add Asana and Preview links above.
  • Conduct thorough self-review.
  • Add or update tests as appropriate.
  • Write a useful description (above) to give reviewers appropriate context.
  • Add release notes to the appropriate section (above).
  • Conduct reasonable cross browser testing for both compatibility and responsive behavior (We have a Cross Browser Testing account for this, if you don't have access, just ask!).
  • Conduct reasonable accessibility review (use the WAS as a guide or an axe browser plugin until we establish more formal checks).
  • Identify (in the description above) and document (add Asana tasks on this board) any technical debt that you're aware of, but are not addressing as part of this PR.

@vercel
Copy link

vercel bot commented Feb 17, 2021

This pull request is being automatically deployed with Vercel (learn more).
To see the status of your deployment, click below or on the icon next to each commit.

πŸ” Inspect: https://vercel.com/hashicorp/react-components/GbPq6XqvzMzNP2dbwrEXYAkYhK8V
βœ… Preview: https://react-components-git-zsdocs-sidenav-refactor-hashicorp.vercel.app

@zchsh zchsh changed the title WIP - refactor DocsSidenav per RFC [WIP] Refactor DocsSidenav per RFC Feb 17, 2021
@@ -0,0 +1,15 @@
const fetch = require('isomorphic-unfetch')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This stuff (remote file fetching from GH) seems kind of specific to the packer registry implementation. πŸ’­ I'm wondering if it makes sense to include the remote file fetching in this package. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great point - have moved this out into the Packer repo πŸ‘

@@ -0,0 +1,237 @@
@custom-media --mobile-viewports (max-width: 939px);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL!

@zchsh zchsh changed the title [WIP] Refactor DocsSidenav per RFC [WIP] Implement MKTG-032 in DocsSidenav and DocsPage Feb 25, 2021
@zchsh zchsh requested a review from brkalow March 6, 2021 04:48
@zchsh
Copy link
Contributor Author

zchsh commented Mar 6, 2021

@jescalan @brkalow welp, not exactly "this afternoon", apologies for the delay - I do feel like the extra time paid off in making things a bit more ship-shape.

Have also proven out the docs-page / docs-sidenav pre-releases pretty extensively in Packer work - hashicorp/packer#10716 has the most up-to-date approach.

Here are the current pre-releases:

@hashicorp/react-docs-page@10.9.4-alpha.53
@hashicorp/react-docs-sidenav@6.1.1-alpha.53
@hashicorp/react-glossary-page => 0.2.4-alpha.54

Let me know if there's any part of the PR I can add more detail on.

Side note: I want to try out the GlossaryPage pre-release - @brkalow are we using that in prod yet? Or is there a PR I could work off of to make sure it works?

const handleMenuTransitionEnd = useCallback(() => {
setIsMenuFullyHidden(!isMobileOpen)
}, [isMobileOpen, setIsMenuFullyHidden])
useEventListener('transitionend', handleMenuTransitionEnd, menuRef.current)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had some fun trying to get the menu hide / show working as expected from both a visual and screen-reader standpoint. I think this approach works, and hopefully it doesn't feel too wild - I may have gone a bit overboard with the comments here.

// we want to close the mobile rather than keep it open
useEffect(() => {
setIsMobileOpen(false)
}, [pathname])
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes an issue where the mobile menu didn't close on client-side navigation - shoutout to @brkalow for suggesting this solution πŸ™‡

content={filteredContent || []}
currentPath={currentPath}
Link={Link}
/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've changed from a function here to a component, it just felt a little clearer when trying to map how the rendering plays out to how the nav-data is structured in terms of branch and leave nodes. The way things work is still really similar with the recursive rendering etc.

Copy link
Contributor

@brkalow brkalow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really appreciate the improvements and enhancements you made as part of this. The implementation looks solid. Great tests!

Way to leave it better than you found it ❀️

order,
pagePath,
navData,
currentPath,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the clarity!

mainBranch = 'main',
order,
pagePath,
navData,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ’―

navData,
currentPath,
pageTitle,
baseRoute,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think baseRoute makes sense. I'll keep this in mind as I'm using the supbath terminology throughout the versioned docs work.

}
})

describe('<DocsPage />', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing work!

Comment on lines +102 to +111
// If it's not a landing page, then we search
// through our navData to find the node with a path
// that matches the pathArray we're looking for.
function flattenRoutes(nodes) {
return nodes.reduce((acc, n) => {
if (!n.routes) return acc.concat(n)
return acc.concat(flattenRoutes(n.routes))
}, [])
}
const allNodes = flattenRoutes(navData)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially a future optimization, but we might consider moving this function to the top level and memoizing it so we only flatten the nav nodes once. I don't think we need to do it right away though!

@@ -0,0 +1,206 @@
#! /usr/bin/env node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great! We'll definitely need this for versioned docs transformation. I wonder where this should live with that in mind πŸ€”

See here for how I'm tentatively thinking of structuring transforms: https://github.com/hashicorp/mktg-versioned-docs/tree/main/src/transforms

pageTitle="Glossary"
product={{ name: product.name, slug: product.slug }}
subpath="docs"
baseRoute="docs"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not used anywhere, yet. πŸ˜„

Co-authored-by: Bryce Kalow <bkalow@hashicorp.com>
Copy link
Contributor

@jescalan jescalan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a crazy amount of work - very impressive. Thanks for taking this on!

expect(document.title).toBe(`Test Page | Terraform by HashiCorp`)
// Confirm `baseRoute` and `navData` by checking for a rendered link
const activeLeaf = screen.getByText('AWS').parentNode
expect(activeLeaf.nodeName).toBe('A')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a dangerous reliance on html structure here - is there any way we can put a test id directly on the targeted element and select into that

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jescalan ack yeah good point... i was on the fence here since getByText felt right, but parentNode felt wrong.

I've updated to use screen.getByText('AWS').closest('a'), and then changed the assertion to ensure the href on the a tag is correct. Have made similar updates throughout docs-page and docs-sidenav tests πŸ‘

const contentParagraph = screen.getByText('This is a cool docs page!')
expect(contentParagraph.tagName).toBe('P')
// Confirm `product` is passed via class
const contentContainer = contentParagraph.parentNode.parentNode
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here with the DOM traversal, I think this is something we want to try to avoid in tests if we can

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated - now grabbing the .closest('article'). Test might break if content no longer renders an article, but at least less brittle than the current specificity πŸ‘

const jumpToSectionElem = screen.getByText('Jump to Section')
expect(jumpToSectionElem.tagName).toBe('SPAN')
})
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘πŸΌ

// docs catchall route parameters: route/[[...page]].jsx.
// This default parameter ID captures that pattern.
// It can be overridden via options.
const DEFAULT_PARAM_ID = 'page'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ‘πŸΌ

@@ -0,0 +1,206 @@
#! /usr/bin/env node
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder that as well - maybe in the codemods repo?

---

This is a cool component for documentation
DocsSidenav renders a tree of links, with the option to include nested sections. Horizontal dividers can also be included between items.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ˜‚ you didn't like my original description?

@zchsh zchsh force-pushed the zs.docs-sidenav-refactor branch from d219a3f to 8d8092c Compare March 8, 2021 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants