import { ActionList, ActionMenu, Flash } from '@primer/react' import { useState, KeyboardEvent } from 'react' import useSWR from 'swr' import { slug } from 'github-slugger' import cx from 'classnames' import { useMainContext } from 'components/context/MainContext' import { useVersion } from 'components/hooks/useVersion' import { LinkIconHeading } from 'components/article/LinkIconHeading' import { useTranslation } from 'components/hooks/useTranslation' import type { WebhookAction, WebhookData } from './types' import { ParameterTable } from 'components/parameter-table/ParameterTable' import styles from './WebhookPayloadExample.module.scss' type Props = { webhook: WebhookAction } // fetcher passed to useSWR() to get webhook data using the given URL async function webhookFetcher(url: string) { const response = await fetch(url) if (!response.ok) { throw new Error(`${response.status} on ${url}`) } return response.json() } // We manually created decorated webhooks files for GHES versions older than // 3.7, returns whether the given version is one of these versions of GHES. // // TODO: once 3.7 is the oldest supported version of GHES, we won't need this // anymore. function isScrapedGhesVersion(version: ReturnType) { const scrapedVersions = ['3.6', '3.5', '3.4', '3.3', '3.2'] if (!version.isEnterprise) return false // getting the number part e.g. '3.6' from a version string like // 'enterprise-server@3.6' const versionNumber = version.currentVersion.split('@')[1] return scrapedVersions.includes(versionNumber) } export function Webhook({ webhook }: Props) { // Get version for requests to switch webhook action type const version = useVersion() const { t } = useTranslation('products') const context = useMainContext() // Get more user friendly language for the different availability options in // the webhook schema (we can't change it directly in the schema). Note that // we specifically don't want to translate these strings with useTranslation() // like we usually do with strings from data/ui.yml. const rephraseAvailability = context.data.ui.products.webhooks.rephrase_availability // The param that was clicked so we can expand its property
element const [clickedBodyParameterName, setClickedBodyParameterName] = useState('') // The selected webhook action type the user selects via a dropdown const [selectedWebhookActionType, setSelectedWebhookActionType] = useState('') const webhookSlug = slug(webhook.data.category) const webhookFetchUrl = `/api/webhooks/v1?${new URLSearchParams({ category: webhook.data.category, version: version.currentVersion, })}` // callback for the action type dropdown -- besides setting the action type // state, we also want to clear the clicked body param so that no properties // are expanded when we re-render the webhook function handleActionTypeChange(type: string) { setClickedBodyParameterName('') setSelectedWebhookActionType(type) } // callback to trigger useSWR() hook after a nested property is clicked function handleBodyParamExpansion(event: KeyboardEvent) { // need to cast it because 'closest' isn't necessarily available on // event.target const target = event.target as HTMLElement setClickedBodyParameterName(target.closest('details')?.dataset.nestedParamId) } // fires when the webhook action type changes or someone clicks on a nested // body param for the first time. In either case, we now have all the data // for a webhook (i.e. all the data for each action type and all of their // nested parameters) const { data, error } = useSWR( clickedBodyParameterName || selectedWebhookActionType ? webhookFetchUrl : null, webhookFetcher, { revalidateOnFocus: false, } ) const currentWebhookActionType = selectedWebhookActionType || webhook.data.action const currentWebhookAction = (data && data[currentWebhookActionType]) || webhook.data return (

{currentWebhookAction.category}

{t('webhooks.availability')}

    {currentWebhookAction.availability.map((availability) => { // TODO: once 3.7 is the oldest supported version of GHES, we won't need this anymore. if (isScrapedGhesVersion(version)) { return (
  • ) } else { return (
  • {rephraseAvailability[availability] ?? availability}
  • ) } })}

{t('webhooks.webhook_payload_object')}

{error && (

{t('webhooks.action_type_switch_error')}

{error.toString()}

)} {webhook.actionTypes.length > 1 && (

{t('webhooks.action_type')}

{currentWebhookActionType} {webhook.actionTypes.map((type) => { return ( handleActionTypeChange(type)} > {type} ) })}
)}
{webhook.data.payloadExample && ( <>

{t('webhooks.webhook_payload_example')}

{JSON.stringify(webhook.data.payloadExample, null, 2)}
)}
) }