Add new fields to analytics event context: status, page_type, page_document_type (#21115)
* Add new fields to analytics event context: status, page-type, page-document-type * Update schema-event.js * Typescript * Add status meta to error pages * Update DefaultLayout.tsx * Update DefaultLayout.tsx * Update building-and-testing-nodejs-or-python.tsx
This commit is contained in:
@@ -11,7 +11,7 @@ import { useTranslation } from './hooks/useTranslation'
|
||||
|
||||
type Props = { children?: React.ReactNode }
|
||||
export const DefaultLayout = (props: Props) => {
|
||||
const { page, error, isHomepageVersion, currentPathWithoutLanguage, fullUrl } = useMainContext()
|
||||
const { page, error, isHomepageVersion, currentPathWithoutLanguage, fullUrl, status } = useMainContext()
|
||||
const { t } = useTranslation('errors')
|
||||
return (
|
||||
<div className="d-lg-flex">
|
||||
@@ -26,6 +26,7 @@ export const DefaultLayout = (props: Props) => {
|
||||
{/* For Google and Bots */}
|
||||
{page.introPlainText && <meta name="description" content={page.introPlainText} />}
|
||||
|
||||
{/* For local site search indexing */}
|
||||
{page.topics.length > 0 && <meta name="keywords" content={page.topics.join(',')} />}
|
||||
|
||||
{page.hidden && <meta name="robots" content="noindex" />}
|
||||
@@ -41,6 +42,11 @@ export const DefaultLayout = (props: Props) => {
|
||||
)
|
||||
})}
|
||||
|
||||
{/* For analytics events */}
|
||||
{status && <meta name="status" content={status.toString()} />}
|
||||
{page.type && <meta name="page-type" content={page.type} />}
|
||||
{page.documentType && <meta name="page-document-type" content={page.documentType} />}
|
||||
|
||||
{page.fullTitle && (
|
||||
<>
|
||||
<meta property="og:site_name" content="GitHub Docs" />
|
||||
|
||||
@@ -12,6 +12,7 @@ export function GenericError() {
|
||||
<div className="min-h-screen d-flex flex-column">
|
||||
<Head>
|
||||
<title>GitHub Documentation</title>
|
||||
<meta name="status" content="500" />
|
||||
</Head>
|
||||
|
||||
<SimpleHeader />
|
||||
|
||||
@@ -84,6 +84,7 @@ export type MainContextT = {
|
||||
featureFlags: FeatureFlags
|
||||
page: {
|
||||
documentType: string
|
||||
type?: string
|
||||
languageVariants: Array<{ name: string; code: string; hreflang: string; href: string }>
|
||||
topics: Array<string>
|
||||
title: string
|
||||
@@ -104,10 +105,12 @@ export type MainContextT = {
|
||||
|
||||
searchVersions: Record<string, string>
|
||||
nonEnterpriseDefaultVersion: string
|
||||
|
||||
status: number
|
||||
fullUrl: string
|
||||
}
|
||||
|
||||
export const getMainContextFromRequest = (req: any): MainContextT => {
|
||||
export const getMainContext = (req: any, res: any): MainContextT => {
|
||||
return {
|
||||
breadcrumbs: req.context.breadcrumbs || {},
|
||||
activeProducts: req.context.activeProducts,
|
||||
@@ -134,6 +137,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
|
||||
page: {
|
||||
languageVariants: req.context.page.languageVariants,
|
||||
documentType: req.context.page.documentType,
|
||||
type: req.context.page.type || null,
|
||||
title: req.context.page.title,
|
||||
fullTitle: req.context.page.fullTitle,
|
||||
topics: req.context.page.topics || [],
|
||||
@@ -166,6 +170,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
|
||||
featureFlags: {},
|
||||
searchVersions: req.context.searchVersions,
|
||||
nonEnterpriseDefaultVersion: req.context.nonEnterpriseDefaultVersion,
|
||||
status: res.statusCode,
|
||||
fullUrl: req.protocol + '://' + req.get('host') + req.originalUrl,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,11 @@ type SendEventProps = {
|
||||
preference_value?: string
|
||||
}
|
||||
|
||||
function getMetaContent(name: string) {
|
||||
const metaTag = document.querySelector(`meta[name="${name}"]`) as HTMLMetaElement
|
||||
return metaTag?.content
|
||||
}
|
||||
|
||||
export function sendEvent({ type, version = '1.0.0', ...props }: SendEventProps) {
|
||||
let site_language = location.pathname.split('/')[1]
|
||||
if (location.pathname.startsWith('/playground')) {
|
||||
@@ -91,6 +96,9 @@ export function sendEvent({ type, version = '1.0.0', ...props }: SendEventProps)
|
||||
search: location.search,
|
||||
href: location.href,
|
||||
site_language,
|
||||
page_document_type: getMetaContent('page-document-type'),
|
||||
page_type: getMetaContent('page-type'),
|
||||
status: Number(getMetaContent('status') || 0),
|
||||
|
||||
// Device information
|
||||
// os, os_version, browser, browser_version:
|
||||
|
||||
@@ -63,6 +63,22 @@ const context = {
|
||||
description: 'The language the user is viewing.',
|
||||
enum: Object.keys(languages),
|
||||
},
|
||||
page_document_type: {
|
||||
type: 'string',
|
||||
description: 'The generic page document type based on URL path.',
|
||||
enum: ['homepage', 'early-access', 'product', 'category', 'mapTopic', 'article'], // get-document-type.js
|
||||
},
|
||||
page_type: {
|
||||
type: 'string',
|
||||
description: 'Optional page type from the content frontmatter.',
|
||||
enum: ['overview', 'quick_start', 'tutorial', 'how_to', 'reference'], // frontmatter.js
|
||||
},
|
||||
status: {
|
||||
type: 'number',
|
||||
description: 'The HTTP response status code of the main page HTML.',
|
||||
minimum: 0,
|
||||
maximum: 999,
|
||||
},
|
||||
|
||||
// Device information
|
||||
os: {
|
||||
|
||||
@@ -16,8 +16,7 @@ router.post('/', async function postEvents(req, res, next) {
|
||||
const fields = omit(req.body, '_csrf')
|
||||
|
||||
if (!ajv.validate(schema, fields)) {
|
||||
if (isDev) console.log(ajv.errorsText())
|
||||
return res.status(400).json({})
|
||||
return res.status(400).json(isDev ? ajv.errorsText() : {})
|
||||
}
|
||||
|
||||
if (req.hydro.maySend()) {
|
||||
|
||||
@@ -9,6 +9,7 @@ const Custom404 = () => {
|
||||
<div className="min-h-screen d-flex flex-column">
|
||||
<Head>
|
||||
<title>404 - Page not found</title>
|
||||
<meta name="status" content="404" />
|
||||
</Head>
|
||||
|
||||
<SimpleHeader />
|
||||
|
||||
@@ -8,11 +8,7 @@ import displayToolSpecificContent from 'components/lib/display-tool-specific-con
|
||||
import localization from 'components/lib/localization'
|
||||
import wrapCodeTerms from 'components/lib/wrap-code-terms'
|
||||
|
||||
import {
|
||||
MainContextT,
|
||||
MainContext,
|
||||
getMainContextFromRequest,
|
||||
} from 'components/context/MainContext'
|
||||
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
|
||||
|
||||
import {
|
||||
getProductLandingContextFromRequest,
|
||||
@@ -100,10 +96,11 @@ export default GlobalPage
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||
const req = context.req as any
|
||||
const res = context.res as any
|
||||
|
||||
return {
|
||||
props: {
|
||||
mainContext: getMainContextFromRequest(req),
|
||||
mainContext: getMainContext(req, res),
|
||||
productLandingContext: getProductLandingContextFromRequest(req),
|
||||
productSubLandingContext: getProductSubLandingContextFromRequest(req),
|
||||
tocLandingContext: getTocLandingContextFromRequest(req),
|
||||
|
||||
@@ -1,11 +1,7 @@
|
||||
import { GetServerSideProps } from 'next'
|
||||
import { BeakerIcon, ZapIcon } from '@primer/octicons-react'
|
||||
|
||||
import {
|
||||
MainContextT,
|
||||
MainContext,
|
||||
getMainContextFromRequest,
|
||||
} from 'components/context/MainContext'
|
||||
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
|
||||
|
||||
import {
|
||||
PlaygroundContextProvider,
|
||||
@@ -88,10 +84,11 @@ function PageInner() {
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||
const req = context.req as any
|
||||
const res = context.res as any
|
||||
|
||||
return {
|
||||
props: {
|
||||
mainContext: getMainContextFromRequest(req),
|
||||
mainContext: getMainContext(req, res),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { GetServerSideProps } from 'next'
|
||||
import { Liquid } from 'liquidjs'
|
||||
import {
|
||||
MainContextT,
|
||||
MainContext,
|
||||
getMainContextFromRequest,
|
||||
} from 'components/context/MainContext'
|
||||
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
|
||||
import { DefaultLayout } from 'components/DefaultLayout'
|
||||
import { GHAEReleaseNotes } from 'components/release-notes/GHAEReleaseNotes'
|
||||
import { GHESReleaseNotes } from 'components/release-notes/GHESReleaseNotes'
|
||||
@@ -40,11 +36,12 @@ export default function ReleaseNotes({
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||
const req = context.req as any
|
||||
const res = context.res as any
|
||||
const currentVersion = req.context.allVersions[req.context.currentVersion]
|
||||
const { latestPatch = '', latestRelease = '' } = req.context
|
||||
return {
|
||||
props: {
|
||||
mainContext: getMainContextFromRequest(req),
|
||||
mainContext: getMainContext(req, res),
|
||||
currentVersion,
|
||||
ghesContext: {
|
||||
currentVersion,
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
import { GetServerSideProps } from 'next'
|
||||
|
||||
import {
|
||||
MainContextT,
|
||||
MainContext,
|
||||
getMainContextFromRequest,
|
||||
} from 'components/context/MainContext'
|
||||
import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
|
||||
import { Breadcrumbs } from 'components/Breadcrumbs'
|
||||
import { DefaultLayout } from 'components/DefaultLayout'
|
||||
import { useEffect, useRef } from 'react'
|
||||
@@ -55,10 +51,11 @@ export default function GQLExplorer({ mainContext, graphqlExplorerUrl }: Props)
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||
const req = context.req as any
|
||||
const res = context.res as any
|
||||
|
||||
return {
|
||||
props: {
|
||||
mainContext: getMainContextFromRequest(req),
|
||||
mainContext: getMainContext(req, res),
|
||||
graphqlExplorerUrl: req.context.graphql.explorerUrl,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { GetServerSideProps } from 'next'
|
||||
import {
|
||||
MainContextT,
|
||||
MainContext,
|
||||
getMainContextFromRequest,
|
||||
getMainContext,
|
||||
useMainContext,
|
||||
} from 'components/context/MainContext'
|
||||
|
||||
@@ -134,10 +134,11 @@ function LandingPage(props: LandingPageProps) {
|
||||
|
||||
export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
|
||||
const req = context.req as any
|
||||
const res = context.res as any
|
||||
|
||||
return {
|
||||
props: {
|
||||
mainContext: getMainContextFromRequest(req),
|
||||
mainContext: getMainContext(req, res),
|
||||
gettingStartedLinks: req.context.featuredLinks.gettingStarted.map(
|
||||
({ title, href, intro }: any) => ({ title, href, intro })
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user