diff --git a/src/pages/hcp/api-docs/vault-secrets/[[...page]].tsx b/src/pages/hcp/api-docs/vault-secrets/[[...page]].tsx new file mode 100644 index 0000000000..5a5c3632eb --- /dev/null +++ b/src/pages/hcp/api-docs/vault-secrets/[[...page]].tsx @@ -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 `` with custom operation path truncation + * for HCP Vault secrets. + */ +function HcpVaultSecretsApiDocsView(props: ApiDocsViewProps) { + return ( + ( + + )} + /> + ) +} + +/** + * Get static paths, using `versionData` fetched from GitHub. + */ +export const getStaticPaths: GetStaticPaths = 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 diff --git a/src/views/api-docs-view/api-docs-view.module.css b/src/views/api-docs-view/api-docs-view.module.css index f4206eebc1..508a92fa03 100644 --- a/src/views/api-docs-view/api-docs-view.module.css +++ b/src/views/api-docs-view/api-docs-view.module.css @@ -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 { diff --git a/src/views/api-docs-view/components/path-truncation-aside/index.tsx b/src/views/api-docs-view/components/path-truncation-aside/index.tsx index bc7e18a65d..eb299fe06e 100644 --- a/src/views/api-docs-view/components/path-truncation-aside/index.tsx +++ b/src/views/api-docs-view/components/path-truncation-aside/index.tsx @@ -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 `` in each operation intro. + * + * This regex matches a standard prefix in HCP Vault Secrets API paths: + * /secrets//organizations/{location.organization_id}/projects/{location.project_id} + * where `` is a date-based version in the format YYYY-MM-DD. + */ +function truncateVaultSecretsOperationPath(path: string) { + return path.replace( + /\/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 `` in each operation intro. + * + * This regex matches a standard prefix in HCP Packer API paths: + * /packer//organizations/{location.organization_id}/projects/{location.project_id} + * where `` is a date-based version in the format YYYY-MM-DD. */ function truncatePackerOperationPath(path: string) { return path.replace( @@ -39,4 +58,8 @@ function PathTruncationAside({ path }: { path: string }) { ) } -export { PathTruncationAside, truncatePackerOperationPath } +export { + PathTruncationAside, + truncatePackerOperationPath, + truncateVaultSecretsOperationPath, +} diff --git a/src/views/api-docs-view/index.tsx b/src/views/api-docs-view/index.tsx index 4f4e2077c0..6f885ed6d4 100644 --- a/src/views/api-docs-view/index.tsx +++ b/src/views/api-docs-view/index.tsx @@ -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. @@ -73,8 +73,10 @@ function ApiDocsView({ } /> {serviceData ? ( - <> -

{serviceData.name}

+
+ {serviceData.name ? ( +

{serviceData.name}

+ ) : null} {serviceData.operations.map((operation: OperationObjectType) => { return ( ) })} - +
) : (

Select a service from the sidebar.

)}