Skip to content

Commit

Permalink
Add validated-patterns content (#2666)
Browse files Browse the repository at this point in the history
* created new validated patterns page based on waf content

* remove debug msg

* replace placeholders

* Add not found to validated patterns content

Co-authored-by: Heat Hamilton <[email protected]>

* Apply suggestions from code review

Co-authored-by: Heat Hamilton <[email protected]>

* Update src/content/validated-patterns/index.json

Co-authored-by: Heat Hamilton <[email protected]>

* make image optional for hero

* make image optional for hero

---------

Co-authored-by: Heat Hamilton <[email protected]>
  • Loading branch information
im2nguyen and heatlikeheatwave authored Jan 17, 2025
1 parent 633c4a6 commit e913afc
Show file tree
Hide file tree
Showing 34 changed files with 959 additions and 22 deletions.
6 changes: 5 additions & 1 deletion scripts/content-repo-preview/builders/developer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ export function DeveloperPreviewBuilder(product) {
/**
* Remove specific page files to speed up preview builds:
* - /src/pages/well-architected-framework
* - /src/pages/validated-patterns
*/
const pagesDir = path.join(cwd, 'src', 'pages')
const pagesDirsToRemove = ['well-architected-framework']
const pagesDirsToRemove = [
'well-architected-framework',
'validated-patterns',
]

/**
* Remove validated designs paths from docs previews
Expand Down
5 changes: 4 additions & 1 deletion scripts/generate-tutorial-variant-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,10 @@ async function getVariantRewrites() {
const [product, collectionFilename] = collection.slug.split('/')
let path = `/${product}/tutorials/${collectionFilename}/${tutorialFilename}`

if (product === 'well-architected-framework') {
if (
product === 'well-architected-framework' ||
product === 'validated-patterns'
) {
path = `/${product}/${collectionFilename}/${tutorialFilename}`
}

Expand Down
2 changes: 1 addition & 1 deletion src/components/branded-card/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import patternWaypoint from './img/waypoint.png'
import s from './branded-card.module.css'

const PATTERN_IMG_MAP: Record<
Exclude<ProductSlug, 'well-architected-framework'>,
Exclude<ProductSlug, 'well-architected-framework' | 'validated-patterns'>,
StaticImageData
> = {
boundary: patternBoundary,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ const generateBasicSuggestedPages = (productSlug: ProductSlug) => {
* link to the Tutorials Library.
*/
const EXTRA_PAGES: Record<
Exclude<ProductSlug, 'sentinel' | 'well-architected-framework'>,
Exclude<
ProductSlug,
'sentinel' | 'well-architected-framework' | 'validated-patterns'
>,
SuggestedPageProps[]
> = {
boundary: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,10 @@ const DEFAULT_GITHUB_LINK = 'https://github.com/hashicorp'
const DEFAULT_SUPPORT_LINK = 'https://www.hashicorp.com/customer-success'

const COMMUNITY_LINKS_BY_PRODUCT: {
[key in Exclude<ProductSlug, 'well-architected-framework'>]: string
[key in Exclude<
ProductSlug,
'well-architected-framework' | 'validated-patterns'
>]: string
} = {
boundary: 'https://discuss.hashicorp.com/c/boundary/50',
consul: 'https://discuss.hashicorp.com/c/consul/29',
Expand All @@ -47,7 +50,7 @@ const COMMUNITY_LINKS_BY_PRODUCT: {
const GITHUB_LINKS_BY_PRODUCT_SLUG: {
[key in Exclude<
ProductSlug,
'waypoint' | 'well-architected-framework'
'waypoint' | 'well-architected-framework' | 'validated-patterns'
>]: string
} = {
boundary: 'https://github.com/hashicorp/boundary',
Expand Down
5 changes: 4 additions & 1 deletion src/components/try-hcp-callout/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,10 @@ export function hasHcpCalloutContent(s: string): s is ProductSlugWithContent {
}

export const tryHcpCalloutContent: Record<
Exclude<ProductSlugWithContent, 'well-architected-framework'>,
Exclude<
ProductSlugWithContent,
'well-architected-framework' | 'validated-patterns'
>,
HcpCalloutContent
> = {
terraform: {
Expand Down
12 changes: 12 additions & 0 deletions src/content/validated-patterns/index.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"sidebarCategories": [],
"landingPage": {
"hero": {
"heading": "Validated Patterns"
},
"overview": {
"heading": "What are Validated Patterns?",
"body": "HashiCorp Validated Patterns provide prescriptive guidance on integrating HashiCorp and partner technologies."
}
}
}
4 changes: 4 additions & 0 deletions src/data/validated-patterns.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"slug": "validated-patterns",
"name": "Validated Patterns"
}
2 changes: 1 addition & 1 deletion src/lib/learn-client/api/page/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export type PageSlugOption =
| ProductOption
| ThemeOption.cloud
| 'well-architected-framework'

| 'validated-patterns'
export async function getPage(
slug: PageSlugOption
): Promise<ClientProductPage> {
Expand Down
3 changes: 2 additions & 1 deletion src/lib/learn-client/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ export const ProductPageSchema = Joi.object({
.valid(
...Object.values(ProductOption),
ThemeOption.cloud,
'well-architected-framework'
'well-architected-framework',
'validated-patterns'
)
.required(),
pageData: Joi.object({
Expand Down
1 change: 1 addition & 0 deletions src/lib/learn-client/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ export enum ProductOption {

export enum SectionOption {
'well-architected-framework' = 'well-architected-framework',
'validated-patterns' = 'validated-patterns',
}

export enum EditionOption {
Expand Down
10 changes: 8 additions & 2 deletions src/lib/products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ import {
* could use to simplify our setup... It feels a bit convoluted right now.
*/
const productSlugsToNames: {
[slug in Exclude<ProductSlug, 'well-architected-framework'>]: ProductName
[slug in Exclude<
ProductSlug,
'well-architected-framework' | 'validated-patterns'
>]: ProductName
} = {
hcp: 'HashiCorp Cloud Platform',
terraform: 'Terraform',
Expand All @@ -96,7 +99,10 @@ const productSlugsToNames: {
* A map of product slugs to their "dot io" site hostname.
*/
const productSlugsToHostNames: {
[slug in Exclude<ProductSlug, 'well-architected-framework'>]: string
[slug in Exclude<
ProductSlug,
'well-architected-framework' | 'validated-patterns'
>]: string
} = {
boundary: 'boundaryproject.io',
consul: 'consul.io',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ describe('getIsExternalLearnLink', () => {
['/vault', true],
['/waypoint', true],
['/well-architected-framework', true],
['/validated-patterns', true],
['/cloud', true],
])
})
Expand All @@ -70,6 +71,7 @@ describe('getIsExternalLearnLink', () => {
['/collections/vault/collection-slug', true],
['/collections/waypoint/collection-slug', true],
['/collections/well-architected-framework/collection-slug', true],
['/collections/validated-patterns/collection-slug', true],
['/collections/cloud/collection-slug', true],
])
})
Expand All @@ -91,6 +93,7 @@ describe('getIsExternalLearnLink', () => {
['/tutorials/vault/tutorial-slug', true],
['/tutorials/waypoint/tutorial-slug', true],
['/tutorials/well-architected-framework/tutorial-slug', true],
['/tutorials/validated-patterns/tutorial-slug', true],
['/tutorials/cloud/tutorial-slug', true],
]

Expand All @@ -114,6 +117,8 @@ describe('getIsExternalLearnLink', () => {
['/waypoint/tutorials/collection-slug/tutorial-slug', false],
['/well-architected-framework/collection-slug', false],
['/well-architected-framework/collection-slug/tutorial-slug', false],
['/validated-patterns/collection-slug', false],
['/validated-patterns/collection-slug/tutorial-slug', false],

['/hcp/tutorials/collection-slug', false],
['/hcp/tutorials/collection-slug/tutorial-slug', false],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ describe('rewriteExternalCollectionLink', () => {
'/collections/well-architected-framework/com',
'/well-architected-framework/com',
],
['/collections/validated-patterns/nomad', '/validated-patterns/nomad'],
['/collections/cloud/networking', '/hcp/tutorials/networking'],
['/collections/hcp/networking', '/hcp/tutorials/networking'],
])
Expand All @@ -78,6 +79,10 @@ describe('rewriteExternalCollectionLink', () => {
'/collections/well-architected-framework/com?paramA=valueA',
'/well-architected-framework/com?paramA=valueA',
],
[
'/collections/validated-patterns/nomad?paramA=valueA',
'/validated-patterns/nomad?paramA=valueA',
],
[
'/collections/cloud/networking?paramA=valueA',
'/hcp/tutorials/networking?paramA=valueA',
Expand Down Expand Up @@ -107,6 +112,10 @@ describe('rewriteExternalCollectionLink', () => {
'/collections/well-architected-framework/com#test-hash',
'/well-architected-framework/com#test-hash',
],
[
'/collections/validated-patterns/nomad#test-hash',
'/validated-patterns/nomad#test-hash',
],
[
'/collections/cloud/networking#test-hash',
'/hcp/tutorials/networking#test-hash',
Expand Down Expand Up @@ -136,6 +145,10 @@ describe('rewriteExternalCollectionLink', () => {
'/collections/well-architected-framework/com?paramA=valueA#test-hash',
'/well-architected-framework/com?paramA=valueA#test-hash',
],
[
'/collections/validated-patterns/nomad?paramA=valueA#test-hash',
'/validated-patterns/nomad?paramA=valueA#test-hash',
],
[
'/collections/cloud/networking?paramA=valueA#test-hash',
'/hcp/tutorials/networking?paramA=valueA#test-hash',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const MOCK_TUTORIAL_MAP = {
'cloud/amazon-peering-hcp': '/hcp/tutorials/networking/amazon-peering-hcp',
'well-architected-framework/tutorial':
'/well-architected-framework/collection/tutorial',
'validated-patterns/tutorial': '/validated-patterns/collection/tutorial',
}

const testEachCase = (cases: string[][]) => {
Expand Down Expand Up @@ -57,6 +58,10 @@ describe('rewriteExternalTutorialLink', () => {
'/tutorials/well-architected-framework/tutorial',
MOCK_TUTORIAL_MAP['well-architected-framework/tutorial'],
],
[
'/tutorials/validated-patterns/tutorial',
MOCK_TUTORIAL_MAP['validated-patterns/tutorial'],
],
['/tutorials/not-a-beta-product/tutorial', undefined],
['/tutorials/vault/tutorial-does-not-exist', undefined],
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import remark from 'remark'
import { rewriteTutorialLinksPlugin } from 'lib/remark-plugins/rewrite-tutorial-links'
import { productSlugs, productSlugsToHostNames } from 'lib/products'
import path from 'path'

// HELPERS ------------------------------------------------------

Expand Down Expand Up @@ -66,7 +67,9 @@ const TEST_MD_LINKS = {
productDocsLinkUseCases:
'[link to vault use cases](https://www.vaultproject.io/use-cases)',
wafTutorialLink:
'[waf link](/tutorials/well-architected-framework/cloud-operating-model)',
'[link to waf](/tutorials/well-architected-framework/cloud-operating-model)',
validatedPatternsTutorialLink:
'[link to validated patterns](/tutorials/validated-patterns/workload-modernization-with-traefik)',
}

/**
Expand All @@ -83,6 +86,8 @@ const MOCK_TUTORIALS_MAP = {
'waypoint/get-started': '/waypoint/tutorials/get-started-docker/get-started',
'well-architected-framework/cloud-operating-model':
'/well-architected-framework/com/cloud-operating-model',
'validated-patterns/workload-modernization-with-traefik':
'/validated-patterns/nomad/workload-modernization-with-traefik',
'cloud/get-started-vault': '/vault/tutorials/cloud/get-started-vault',
}

Expand Down Expand Up @@ -329,4 +334,15 @@ describe('rewriteTutorialLinks remark plugin', () => {
'/well-architected-framework/com/cloud-operating-model'
)
})

test('Validated patterns tutorial link should be rewritten properly', async () => {
const contents = await remark()
.use(rewriteTutorialLinksPlugin, { tutorialMap: MOCK_TUTORIALS_MAP })
.process(TEST_MD_LINKS.validatedPatternsTutorialLink)

const newPath = isolatePathFromMarkdown(String(contents))
expect(newPath).toBe(
'/validated-patterns/nomad/workload-modernization-with-traefik'
)
})
})
72 changes: 72 additions & 0 deletions src/pages/validated-patterns/[...tutorialSlug]/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

import { getCollectionsBySection } from 'lib/learn-client/api/collection'
import {
Collection as ApiCollection,
TutorialLite as ApiTutorialLite,
} from 'lib/learn-client/types'
import { splitProductFromFilename } from 'views/tutorial-view/utils'
import ValidatedPatternsTutorialView from 'views/validated-patterns/tutorial-view'
import { getValidatedPatternsTutorialViewProps } from 'views/validated-patterns/tutorial-view/server'
import validatedPatternsData from 'data/validated-patterns.json'
import { ValidatedPatternsTutorialViewProps } from 'views/validated-patterns/types'
import { GetStaticPropsContext } from 'next'
import { getStaticPathsFromAnalytics } from 'lib/get-static-paths-from-analytics'

export async function getStaticProps({
params,
}: GetStaticPropsContext<{ tutorialSlug: [string, string] }>): Promise<
{ props: ValidatedPatternsTutorialViewProps } | { notFound: boolean }
> {
return { notFound: true }
const props = await getValidatedPatternsTutorialViewProps(params.tutorialSlug)

// If the tutorial doesn't exist, hit the 404
if (!props) {
return { notFound: true }
}
return props
}

export async function getStaticPaths() {
const allCollections = await getCollectionsBySection(validatedPatternsData.slug)
let paths = []
allCollections.forEach((c: ApiCollection) => {
const collectionSlug = splitProductFromFilename(c.slug)
c.tutorials.forEach(({ slug }: { slug: ApiTutorialLite['slug'] }) =>
paths.push({
params: {
tutorialSlug: [collectionSlug, splitProductFromFilename(slug)],
},
})
)
})

// For hashicorp/tutorials PR previews, skip the call to determine paths
// from analytics, and statically build all paths.
if (process.env.HASHI_ENV === 'tutorials-preview') {
return {
paths: paths,
fallback: false,
}
}

try {
paths = await getStaticPathsFromAnalytics({
param: 'tutorialSlug',
limit: __config.learn.max_static_paths ?? 0,
pathPrefix: `/validated-patterns`,
validPaths: paths,
})
} catch {
// In the case of an error, fallback to using the base list of generated paths to ensure we do _some_ form of static generation
paths = paths.slice(0, __config.learn.max_static_paths ?? 0)
}

return { paths, fallback: 'blocking' }
}

export default ValidatedPatternsTutorialView
Loading

0 comments on commit e913afc

Please sign in to comment.