Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions src/pages/hcp/api-docs/vault-secrets/[[...page]].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/**
* Copyright (c) HashiCorp, Inc.
* SPDX-License-Identifier: MPL-2.0
*/

// View
import ApiDocsView from 'views/api-docs-view'
import {
getApiDocsStaticProps,
getApiDocsStaticPaths,
ApiDocsParams,
} from 'views/api-docs-view/server'
import { buildApiDocsBreadcrumbs } from 'views/api-docs-view/server/get-api-docs-static-props/utils'
import { fetchCloudApiVersionData } from 'views/api-docs-view/utils'
// Components
import {
PathTruncationAside,
truncateVaultSecretsOperationPath,
} from 'views/api-docs-view/components'
// Types
import type { OperationObjectType } from 'components/open-api-page/types'
import type { ApiDocsViewProps } from 'views/api-docs-view/types'
import type { GetStaticPaths, GetStaticProps } from 'next'
import { isDeployPreview } from 'lib/env-checks'

/**
* The product slug is used to fetch product data for the layout.
*/
const PRODUCT_SLUG = 'hcp'

/**
* The baseUrl is used to generate
* breadcrumb links, sidebar nav levels, and version switcher links.
*/
const BASE_URL = '/hcp/api-docs/vault-secrets'

/**
* We source version data from a directory in the `hcp-specs` repo.
* See `fetchCloudApiVersionData` for details.
*/
const GITHUB_SOURCE_DIRECTORY = {
owner: 'hashicorp',
repo: 'hcp-specs',
path: 'specs/cloud-vault-secrets',
ref: 'main',
}

/**
* Render `<ApiDocsView />` with custom operation path truncation
* for HCP Vault secrets.
*/
function HcpVaultSecretsApiDocsView(props: ApiDocsViewProps) {
return (
<ApiDocsView
{...props}
massagePathFn={truncateVaultSecretsOperationPath}
renderOperationIntro={({ data }: { data: OperationObjectType }) => (
<PathTruncationAside path={data.__path} />
)}
/>
)
}

/**
* Get static paths, using `versionData` fetched from GitHub.
*/
export const getStaticPaths: GetStaticPaths<ApiDocsParams> = async () => {
// If we are in a deploy preview, don't pre-render any paths
if (isDeployPreview()) {
return { paths: [], fallback: 'blocking' }
}
// Otherwise, fetch version data, and use that to generate paths
const versionData = await fetchCloudApiVersionData(GITHUB_SOURCE_DIRECTORY)
return await getApiDocsStaticPaths({ productSlug: PRODUCT_SLUG, versionData })
}

/**
* Get static props, using `versionData` fetched from GitHub.
*
* We need all version data for the version selector,
* and of course we need specific data for the current version.
*/
export const getStaticProps: GetStaticProps<
ApiDocsViewProps,
ApiDocsParams
> = async ({ params }: { params: ApiDocsParams }) => {
// Fetch all version data, based on remote `stable` & `preview` subfolders
const versionData = await fetchCloudApiVersionData(GITHUB_SOURCE_DIRECTORY)
// If we can't find any version data at all, render a 404 page.
if (!versionData) {
return { notFound: true }
}
// Return static props
const staticPropsResult = await getApiDocsStaticProps({
productSlug: PRODUCT_SLUG,
baseUrl: BASE_URL,
pathParts: params.page,
versionData,
buildCustomBreadcrumbs: ({ productData, serviceData, versionId }) => {
return buildApiDocsBreadcrumbs({
productData,
// HCP API docs at `/api-docs` are not linkable, so we pass url=null
apiDocs: { name: 'API', url: null },
serviceData,
versionId,
})
},
})
/**
* Shims specific to HCP Vault Secrets
*/
if (!('props' in staticPropsResult)) {
return staticPropsResult
}
// We shim in the removal of the service name, as it's redundant.
staticPropsResult.props.serviceData.name = ''
// Return the static props results with shimmed modifications
return staticPropsResult
}

export default HcpVaultSecretsApiDocsView
8 changes: 7 additions & 1 deletion src/views/api-docs-view/api-docs-view.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
* SPDX-License-Identifier: MPL-2.0
*/

.serviceData {
margin-top: 32px;
display: flex;
flex-direction: column;
}

.serviceHeading {
composes: hds-typography-display-400 from global;
font-weight: var(--token-typography-font-weight-bold);
margin: 32px 0 16px 0;
margin-bottom: 16px;
}

.sidebarPrompt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,28 @@
import DevDotContent from 'components/dev-dot-content'
import CodeBlock from '@hashicorp/react-code-block'

/**
* Truncates HCP Vault Secrets API operation paths for clarity.
* Intended to be used with a `<PathTruncationAside />` in each operation intro.
*
* This regex matches a standard prefix in HCP Vault Secrets API paths:
* /secrets/<version>/organizations/{location.organization_id}/projects/{location.project_id}
* where `<version>` is a date-based version in the format YYYY-MM-DD.
*/
function truncateVaultSecretsOperationPath(path: string) {
return path.replace(
Copy link
Contributor

@kendallstrautman kendallstrautman Jul 6, 2023

Choose a reason for hiding this comment

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

⛏️ Could we add a bit more clarity as to what the regex should match on in the comment?

Copy link
Contributor Author

@zchsh zchsh Jul 6, 2023

Choose a reason for hiding this comment

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

πŸ™Œ Great call! Added in a comment on this regex matching a standard prefix πŸ‘

/\/secrets\/\d\d\d\d-\d\d-\d\d\/organizations\/\{location.organization_id\}\/projects\/\{location\.project_id\}/,
''
)
}

/**
* Truncates HCP Packer API operation paths for clarity.
* Intended to be used with a `<PathTruncationAside />` in each operation intro.
*
* This regex matches a standard prefix in HCP Packer API paths:
* /packer/<version>/organizations/{location.organization_id}/projects/{location.project_id}
* where `<version>` is a date-based version in the format YYYY-MM-DD.
*/
function truncatePackerOperationPath(path: string) {
return path.replace(
Expand Down Expand Up @@ -39,4 +58,8 @@ function PathTruncationAside({ path }: { path: string }) {
)
}

export { PathTruncationAside, truncatePackerOperationPath }
export {
PathTruncationAside,
truncatePackerOperationPath,
truncateVaultSecretsOperationPath,
}
12 changes: 7 additions & 5 deletions src/views/api-docs-view/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ function ApiDocsView({
/**
* We always render the API docs name in a heading-styled element.
*
* When `serviceData` is provided, we'll render the service name
* When `serviceData.name` is provided, we'll render the service name
* in an `h1` element, as the `serviceName` is a more meaningful page title.
* In such cases, our page heading needs to be a `p` element to avoid
* having multiple `h1` elements on the page.
*/
const pageHeadingTag = serviceData ? 'p' : 'h1'
const pageHeadingTag = serviceData?.name ? 'p' : 'h1'

/**
* We only show the version switcher if we have at least 2 options.
Expand Down Expand Up @@ -73,8 +73,10 @@ function ApiDocsView({
}
/>
{serviceData ? (
<>
<h1 className={s.serviceHeading}>{serviceData.name}</h1>
<div className={s.serviceData}>
{serviceData.name ? (
<h1 className={s.serviceHeading}>{serviceData.name}</h1>
) : null}
{serviceData.operations.map((operation: OperationObjectType) => {
return (
<OperationObject
Expand All @@ -86,7 +88,7 @@ function ApiDocsView({
/>
)
})}
</>
</div>
) : (
<p className={s.sidebarPrompt}>Select a service from the sidebar.</p>
)}
Expand Down