1
0
mirror of synced 2025-12-23 03:44:00 -05:00

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:
Kevin Heis
2021-08-26 14:58:45 -07:00
committed by GitHub
parent 5cf83e524d
commit 4d0e9c70a3
12 changed files with 55 additions and 30 deletions

View File

@@ -11,7 +11,7 @@ import { useTranslation } from './hooks/useTranslation'
type Props = { children?: React.ReactNode } type Props = { children?: React.ReactNode }
export const DefaultLayout = (props: Props) => { export const DefaultLayout = (props: Props) => {
const { page, error, isHomepageVersion, currentPathWithoutLanguage, fullUrl } = useMainContext() const { page, error, isHomepageVersion, currentPathWithoutLanguage, fullUrl, status } = useMainContext()
const { t } = useTranslation('errors') const { t } = useTranslation('errors')
return ( return (
<div className="d-lg-flex"> <div className="d-lg-flex">
@@ -26,6 +26,7 @@ export const DefaultLayout = (props: Props) => {
{/* For Google and Bots */} {/* For Google and Bots */}
{page.introPlainText && <meta name="description" content={page.introPlainText} />} {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.topics.length > 0 && <meta name="keywords" content={page.topics.join(',')} />}
{page.hidden && <meta name="robots" content="noindex" />} {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 && ( {page.fullTitle && (
<> <>
<meta property="og:site_name" content="GitHub Docs" /> <meta property="og:site_name" content="GitHub Docs" />

View File

@@ -12,6 +12,7 @@ export function GenericError() {
<div className="min-h-screen d-flex flex-column"> <div className="min-h-screen d-flex flex-column">
<Head> <Head>
<title>GitHub Documentation</title> <title>GitHub Documentation</title>
<meta name="status" content="500" />
</Head> </Head>
<SimpleHeader /> <SimpleHeader />

View File

@@ -84,6 +84,7 @@ export type MainContextT = {
featureFlags: FeatureFlags featureFlags: FeatureFlags
page: { page: {
documentType: string documentType: string
type?: string
languageVariants: Array<{ name: string; code: string; hreflang: string; href: string }> languageVariants: Array<{ name: string; code: string; hreflang: string; href: string }>
topics: Array<string> topics: Array<string>
title: string title: string
@@ -104,10 +105,12 @@ export type MainContextT = {
searchVersions: Record<string, string> searchVersions: Record<string, string>
nonEnterpriseDefaultVersion: string nonEnterpriseDefaultVersion: string
status: number
fullUrl: string fullUrl: string
} }
export const getMainContextFromRequest = (req: any): MainContextT => { export const getMainContext = (req: any, res: any): MainContextT => {
return { return {
breadcrumbs: req.context.breadcrumbs || {}, breadcrumbs: req.context.breadcrumbs || {},
activeProducts: req.context.activeProducts, activeProducts: req.context.activeProducts,
@@ -134,6 +137,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
page: { page: {
languageVariants: req.context.page.languageVariants, languageVariants: req.context.page.languageVariants,
documentType: req.context.page.documentType, documentType: req.context.page.documentType,
type: req.context.page.type || null,
title: req.context.page.title, title: req.context.page.title,
fullTitle: req.context.page.fullTitle, fullTitle: req.context.page.fullTitle,
topics: req.context.page.topics || [], topics: req.context.page.topics || [],
@@ -166,6 +170,7 @@ export const getMainContextFromRequest = (req: any): MainContextT => {
featureFlags: {}, featureFlags: {},
searchVersions: req.context.searchVersions, searchVersions: req.context.searchVersions,
nonEnterpriseDefaultVersion: req.context.nonEnterpriseDefaultVersion, nonEnterpriseDefaultVersion: req.context.nonEnterpriseDefaultVersion,
status: res.statusCode,
fullUrl: req.protocol + '://' + req.get('host') + req.originalUrl, fullUrl: req.protocol + '://' + req.get('host') + req.originalUrl,
} }
} }

View File

@@ -65,6 +65,11 @@ type SendEventProps = {
preference_value?: string 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) { export function sendEvent({ type, version = '1.0.0', ...props }: SendEventProps) {
let site_language = location.pathname.split('/')[1] let site_language = location.pathname.split('/')[1]
if (location.pathname.startsWith('/playground')) { if (location.pathname.startsWith('/playground')) {
@@ -91,6 +96,9 @@ export function sendEvent({ type, version = '1.0.0', ...props }: SendEventProps)
search: location.search, search: location.search,
href: location.href, href: location.href,
site_language, site_language,
page_document_type: getMetaContent('page-document-type'),
page_type: getMetaContent('page-type'),
status: Number(getMetaContent('status') || 0),
// Device information // Device information
// os, os_version, browser, browser_version: // os, os_version, browser, browser_version:

View File

@@ -63,6 +63,22 @@ const context = {
description: 'The language the user is viewing.', description: 'The language the user is viewing.',
enum: Object.keys(languages), 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 // Device information
os: { os: {

View File

@@ -16,8 +16,7 @@ router.post('/', async function postEvents(req, res, next) {
const fields = omit(req.body, '_csrf') const fields = omit(req.body, '_csrf')
if (!ajv.validate(schema, fields)) { if (!ajv.validate(schema, fields)) {
if (isDev) console.log(ajv.errorsText()) return res.status(400).json(isDev ? ajv.errorsText() : {})
return res.status(400).json({})
} }
if (req.hydro.maySend()) { if (req.hydro.maySend()) {

View File

@@ -9,6 +9,7 @@ const Custom404 = () => {
<div className="min-h-screen d-flex flex-column"> <div className="min-h-screen d-flex flex-column">
<Head> <Head>
<title>404 - Page not found</title> <title>404 - Page not found</title>
<meta name="status" content="404" />
</Head> </Head>
<SimpleHeader /> <SimpleHeader />

View File

@@ -8,11 +8,7 @@ import displayToolSpecificContent from 'components/lib/display-tool-specific-con
import localization from 'components/lib/localization' import localization from 'components/lib/localization'
import wrapCodeTerms from 'components/lib/wrap-code-terms' import wrapCodeTerms from 'components/lib/wrap-code-terms'
import { import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
MainContextT,
MainContext,
getMainContextFromRequest,
} from 'components/context/MainContext'
import { import {
getProductLandingContextFromRequest, getProductLandingContextFromRequest,
@@ -100,10 +96,11 @@ export default GlobalPage
export const getServerSideProps: GetServerSideProps<Props> = async (context) => { export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any const req = context.req as any
const res = context.res as any
return { return {
props: { props: {
mainContext: getMainContextFromRequest(req), mainContext: getMainContext(req, res),
productLandingContext: getProductLandingContextFromRequest(req), productLandingContext: getProductLandingContextFromRequest(req),
productSubLandingContext: getProductSubLandingContextFromRequest(req), productSubLandingContext: getProductSubLandingContextFromRequest(req),
tocLandingContext: getTocLandingContextFromRequest(req), tocLandingContext: getTocLandingContextFromRequest(req),

View File

@@ -1,11 +1,7 @@
import { GetServerSideProps } from 'next' import { GetServerSideProps } from 'next'
import { BeakerIcon, ZapIcon } from '@primer/octicons-react' import { BeakerIcon, ZapIcon } from '@primer/octicons-react'
import { import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
MainContextT,
MainContext,
getMainContextFromRequest,
} from 'components/context/MainContext'
import { import {
PlaygroundContextProvider, PlaygroundContextProvider,
@@ -88,10 +84,11 @@ function PageInner() {
export const getServerSideProps: GetServerSideProps<Props> = async (context) => { export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any const req = context.req as any
const res = context.res as any
return { return {
props: { props: {
mainContext: getMainContextFromRequest(req), mainContext: getMainContext(req, res),
}, },
} }
} }

View File

@@ -1,10 +1,6 @@
import { GetServerSideProps } from 'next' import { GetServerSideProps } from 'next'
import { Liquid } from 'liquidjs' import { Liquid } from 'liquidjs'
import { import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
MainContextT,
MainContext,
getMainContextFromRequest,
} from 'components/context/MainContext'
import { DefaultLayout } from 'components/DefaultLayout' import { DefaultLayout } from 'components/DefaultLayout'
import { GHAEReleaseNotes } from 'components/release-notes/GHAEReleaseNotes' import { GHAEReleaseNotes } from 'components/release-notes/GHAEReleaseNotes'
import { GHESReleaseNotes } from 'components/release-notes/GHESReleaseNotes' import { GHESReleaseNotes } from 'components/release-notes/GHESReleaseNotes'
@@ -40,11 +36,12 @@ export default function ReleaseNotes({
export const getServerSideProps: GetServerSideProps<Props> = async (context) => { export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any const req = context.req as any
const res = context.res as any
const currentVersion = req.context.allVersions[req.context.currentVersion] const currentVersion = req.context.allVersions[req.context.currentVersion]
const { latestPatch = '', latestRelease = '' } = req.context const { latestPatch = '', latestRelease = '' } = req.context
return { return {
props: { props: {
mainContext: getMainContextFromRequest(req), mainContext: getMainContext(req, res),
currentVersion, currentVersion,
ghesContext: { ghesContext: {
currentVersion, currentVersion,

View File

@@ -1,10 +1,6 @@
import { GetServerSideProps } from 'next' import { GetServerSideProps } from 'next'
import { import { MainContextT, MainContext, getMainContext } from 'components/context/MainContext'
MainContextT,
MainContext,
getMainContextFromRequest,
} from 'components/context/MainContext'
import { Breadcrumbs } from 'components/Breadcrumbs' import { Breadcrumbs } from 'components/Breadcrumbs'
import { DefaultLayout } from 'components/DefaultLayout' import { DefaultLayout } from 'components/DefaultLayout'
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
@@ -55,10 +51,11 @@ export default function GQLExplorer({ mainContext, graphqlExplorerUrl }: Props)
export const getServerSideProps: GetServerSideProps<Props> = async (context) => { export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any const req = context.req as any
const res = context.res as any
return { return {
props: { props: {
mainContext: getMainContextFromRequest(req), mainContext: getMainContext(req, res),
graphqlExplorerUrl: req.context.graphql.explorerUrl, graphqlExplorerUrl: req.context.graphql.explorerUrl,
}, },
} }

View File

@@ -3,7 +3,7 @@ import { GetServerSideProps } from 'next'
import { import {
MainContextT, MainContextT,
MainContext, MainContext,
getMainContextFromRequest, getMainContext,
useMainContext, useMainContext,
} from 'components/context/MainContext' } from 'components/context/MainContext'
@@ -134,10 +134,11 @@ function LandingPage(props: LandingPageProps) {
export const getServerSideProps: GetServerSideProps<Props> = async (context) => { export const getServerSideProps: GetServerSideProps<Props> = async (context) => {
const req = context.req as any const req = context.req as any
const res = context.res as any
return { return {
props: { props: {
mainContext: getMainContextFromRequest(req), mainContext: getMainContext(req, res),
gettingStartedLinks: req.context.featuredLinks.gettingStarted.map( gettingStartedLinks: req.context.featuredLinks.gettingStarted.map(
({ title, href, intro }: any) => ({ title, href, intro }) ({ title, href, intro }: any) => ({ title, href, intro })
), ),