Skip to content

Commit

Permalink
chore(support): Clarify the format of support ticket metadata (#23737)
Browse files Browse the repository at this point in the history
  • Loading branch information
Twixes authored Jul 18, 2024
1 parent e494d0e commit 44da61a
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import { SupportForm } from 'lib/components/Support/SupportForm'
import { getPublicSupportSnippet, supportLogic } from 'lib/components/Support/supportLogic'
import React from 'react'
import { billingLogic } from 'scenes/billing/billingLogic'
import { organizationLogic } from 'scenes/organizationLogic'
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
import { teamLogic } from 'scenes/teamLogic'
import { urls } from 'scenes/urls'
import { userLogic } from 'scenes/userLogic'

import { AvailableFeature, ProductKey, SidePanelTab } from '~/types'

Expand Down Expand Up @@ -158,15 +159,16 @@ const SupportFormBlock = ({ onCancel }: { onCancel: () => void }): JSX.Element =

export const SidePanelSupport = (): JSX.Element => {
const { openSidePanel, closeSidePanel } = useActions(sidePanelStateLogic)
const { openEmailForm, closeEmailForm } = useActions(supportLogic)
const { isEmailFormOpen } = useValues(supportLogic)
const { preflight, isCloud } = useValues(preflightLogic)
const { user } = useValues(userLogic)
const region = preflight?.region
const { currentOrganization } = useValues(organizationLogic)
const { currentTeam } = useValues(teamLogic)
const { status } = useValues(sidePanelStatusLogic)

const theLogic = supportLogic({ onClose: () => closeSidePanel(SidePanelTab.Support) })
const { title } = useValues(theLogic)
const { openEmailForm, closeEmailForm } = useActions(theLogic)
const { title, isEmailFormOpen } = useValues(theLogic)

const region = preflight?.region

return (
<>
Expand Down Expand Up @@ -280,7 +282,7 @@ export const SidePanelSupport = (): JSX.Element => {
type="secondary"
status="alt"
to={`https://github.com/PostHog/posthog/issues/new?&labels=enhancement&template=feature_request.yml&debug-info=${encodeURIComponent(
getPublicSupportSnippet(region, user)
getPublicSupportSnippet(region, currentOrganization, currentTeam)
)}`}
icon={<IconFeatures />}
targetBlank
Expand Down
1 change: 1 addition & 0 deletions frontend/src/lib/components/Support/SupportForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export function SupportForm(): JSX.Element | null {
<LemonTextArea
placeholder={SUPPORT_TICKET_TEMPLATES[sendSupportRequest.kind] ?? 'Type your message here'}
data-attr="support-form-content-input"
minRows={5}
{...props}
/>
{objectStorageAvailable && !!user && (
Expand Down
86 changes: 48 additions & 38 deletions frontend/src/lib/components/Support/supportLogic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,64 +6,71 @@ import { urlToAction } from 'kea-router'
import { lemonToast } from 'lib/lemon-ui/LemonToast/LemonToast'
import { uuid } from 'lib/utils'
import posthog from 'posthog-js'
import { organizationLogic } from 'scenes/organizationLogic'
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
import { teamLogic } from 'scenes/teamLogic'
import { userLogic } from 'scenes/userLogic'

import { sidePanelStateLogic } from '~/layout/navigation-3000/sidepanel/sidePanelStateLogic'
import { AvailableFeature, Region, SidePanelTab, TeamType, UserType } from '~/types'
import { AvailableFeature, OrganizationBasicType, Region, SidePanelTab, TeamPublicType, UserType } from '~/types'

import type { supportLogicType } from './supportLogicType'
import { openSupportModal } from './SupportModal'

export function getPublicSupportSnippet(region: Region | null | undefined, user: UserType | null): string {
if (!user || !region) {
export function getPublicSupportSnippet(
cloudRegion: Region | null | undefined,
currentOrganization: OrganizationBasicType | null,
currentTeam: TeamPublicType | null,
includeCurrentLocation = true
): string {
if (!cloudRegion) {
return ''
}
return (
(includeCurrentLocation ? getCurrentLocationLink() : '') +
getSessionReplayLink() +
`\nAdmin: http://go/adminOrg${cloudRegion}/${currentOrganization?.id} (project ID ${currentTeam?.id})` +
getSentryLink(cloudRegion, currentTeam)
).trimStart()
}

return `Session: ${posthog
.get_session_replay_url({ withTimestamp: true, timestampLookBack: 30 })
.replace(window.location.origin + '/replay/', 'http://go/session/')} ${
!window.location.href.includes('settings/project') ? `(at ${window.location.href})` : ''
}\n${`Admin: ${`http://go/adminOrg${region}/${user.organization?.id}`} (Project: ${
teamLogic.values.currentTeamId
})`}\nSentry: ${`http://go/sentry${region}/${user.team?.id}`}`
function getCurrentLocationLink(): string {
const cleanedCurrentUrl = window.location.href.replace(/panel=support[^&]*(&)?/, '').replace(/#$/, '')
return `\nLocation: ${cleanedCurrentUrl}`
}

function getSessionReplayLink(): string {
const link = posthog
const replayUrl = posthog
.get_session_replay_url({ withTimestamp: true, timestampLookBack: 30 })
.replace(window.location.origin + '/replay/', 'http://go/session/')

return `Session: ${link} (at ${window.location.href.replace(/&supportModal=.+($|&)?/, '$1')})`
return `\nSession: ${replayUrl}`
}

function getDjangoAdminLink(
user: UserType | null,
cloudRegion: Region | null | undefined,
currentTeamId: TeamType['id'] | null
currentOrganization: OrganizationBasicType | null,
currentTeam: TeamPublicType | null
): string {
if (!user || !cloudRegion) {
return ''
}
const link = `http://go/admin${cloudRegion}/${user.email}`
return `Admin: ${link} (Organization: '${user.organization?.name}'; Project: ${currentTeamId}:'${user.team?.name}')`
return `\nAdmin: ${link} (organization ID ${currentOrganization?.id}: ${currentOrganization?.name}, project ID ${currentTeam?.id}: ${currentTeam?.name})`
}

function getBillingAdminLink(user: UserType | null): string {
if (!user) {
function getBillingAdminLink(currentOrganization: OrganizationBasicType | null): string {
if (!currentOrganization) {
return ''
}
const link = `http://go/billing/${user.organization?.id}`
return `Billing Admin: ${link} (Organization: '${user.organization?.name}'`
return `\nBilling admin: http://go/billing/${currentOrganization.id}`
}

function getSentryLink(user: UserType | null, cloudRegion: Region | null | undefined): string {
if (!user || !cloudRegion) {
function getSentryLink(cloudRegion: Region | null | undefined, currentTeam: TeamPublicType | null): string {
if (!cloudRegion || !currentTeam) {
return ''
}
const link = `http://go/sentry${cloudRegion}/${user.team?.id}`
return `Sentry: ${link}`
return `\nSentry: http://go/sentry${cloudRegion}/${currentTeam.id}`
}

const SUPPORT_TICKET_KIND_TO_TITLE: Record<SupportTicketKind, string> = {
Expand Down Expand Up @@ -234,7 +241,7 @@ export const SUPPORT_TICKET_TEMPLATES = {
feedback:
"If your request is due to a problem, please describe the problem as best you can.\n\nPlease also describe the solution you'd like to see, and any alternatives you considered.\n\nYou can add images below to help illustrate your request, if needed!",
support:
"Please explain as fully as possible what it is you're trying to do, and what you'd like help with.\n\nIf your question involves an existing insight or dashboard, please include a link to it.",
"Please explain as fully as possible what you're aiming to do, and what you'd like help with.\n\nIf your question involves an existing insight or dashboard, please include a link to it.",
}

export function getURLPathToTargetArea(pathname: string): SupportTicketTargetArea | null {
Expand Down Expand Up @@ -422,27 +429,30 @@ export const supportLogic = kea<supportLogicType>([
},
],
comment: {
body: (
body:
message +
`\n\n-----` +
`\nKind: ${kind}` +
`\nTarget area: ${target_area}` +
`\nReport event: http://go/ticketByUUID/${zendesk_ticket_uuid}` +
'\n' +
getCurrentLocationLink() +
getSessionReplayLink() +
'\n' +
getDjangoAdminLink(userLogic.values.user, cloudRegion, teamLogic.values.currentTeamId) +
'\n' +
'PoE mode: ' +
(teamLogic.values.currentTeam?.modifiers?.personsOnEventsMode ??
teamLogic.values.currentTeam?.default_modifiers?.personsOnEventsMode ??
'disabled') +
'\n' +
`\nReport event: http://go/ticketByUUID/${zendesk_ticket_uuid}` +
getDjangoAdminLink(
userLogic.values.user,
cloudRegion,
organizationLogic.values.currentOrganization,
teamLogic.values.currentTeam
) +
(target_area === 'billing' || target_area === 'login' || target_area === 'onboarding'
? getBillingAdminLink(userLogic.values.user) + '\n'
? getBillingAdminLink(organizationLogic.values.currentOrganization)
: '') +
getSentryLink(userLogic.values.user, cloudRegion)
).trim(),
getSentryLink(cloudRegion, teamLogic.values.currentTeam) +
(cloudRegion && teamLogic.values.currentTeam
? '\nPersons-on-events mode for project: ' +
(teamLogic.values.currentTeam.modifiers?.personsOnEventsMode ??
teamLogic.values.currentTeam.default_modifiers?.personsOnEventsMode ??
'unknown')
: ''),
},
},
}
Expand Down
15 changes: 8 additions & 7 deletions frontend/src/scenes/settings/project/ProjectSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import { getPublicSupportSnippet } from 'lib/components/Support/supportLogic'
import { IconRefresh } from 'lib/lemon-ui/icons'
import { Link } from 'lib/lemon-ui/Link'
import { useState } from 'react'
import { organizationLogic } from 'scenes/organizationLogic'
import { preflightLogic } from 'scenes/PreflightCheck/preflightLogic'
import { isAuthenticatedTeam, teamLogic } from 'scenes/teamLogic'
import { userLogic } from 'scenes/userLogic'

import { TimezoneConfig } from './TimezoneConfig'
import { WeekStartConfig } from './WeekStartConfig'
Expand Down Expand Up @@ -91,8 +91,9 @@ export function Bookmarklet(): JSX.Element {
export function ProjectVariables(): JSX.Element {
const { currentTeam, isTeamTokenResetAvailable } = useValues(teamLogic)
const { resetToken } = useActions(teamLogic)
const { currentOrganization } = useValues(organizationLogic)
const { preflight } = useValues(preflightLogic)
const { user } = useValues(userLogic)

const region = preflight?.region

const openDialog = (): void => {
Expand All @@ -115,7 +116,7 @@ export function ProjectVariables(): JSX.Element {
<div className="flex items-start gap-4 flex-wrap">
<div className="flex-1">
<h3 id="project-api-key" className="min-w-[25rem]">
Project API Key
Project API key
</h3>
<p>
You can use this write-only key in any one of{' '}
Expand Down Expand Up @@ -149,20 +150,20 @@ export function ProjectVariables(): JSX.Element {
{region ? (
<div className="flex-1">
<h3 id="project-region" className="min-w-[25rem]">
Project Region
Project region
</h3>
<p>This is the region where your PostHog data is hosted.</p>
<CodeSnippet thing="project region">{`${region} Cloud`}</CodeSnippet>
</div>
) : null}
{region && user ? (
{region && currentOrganization && currentTeam ? (
<div className="flex-1 max-w-full">
<h3 id="debug-info" className="min-w-[25rem]">
Debug information
</h3>
<p>Include this snippet when opening a Feature request or Bug report on GitHub.</p>
<p>Include this snippet when creating an issue (feature request or bug report) on GitHub.</p>
<CodeSnippet compact thing="debug info">
{getPublicSupportSnippet(region, user)}
{getPublicSupportSnippet(region, currentOrganization, currentTeam, false)}
</CodeSnippet>
</div>
) : null}
Expand Down

0 comments on commit 44da61a

Please sign in to comment.