Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web-analytics): Add web analytics tabs #17981

Merged
merged 13 commits into from
Oct 17, 2023
17 changes: 8 additions & 9 deletions frontend/src/layout/navigation/SideBar/SideBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,14 @@ function Pages(): JSX.Element {
onClick: hideSideBarMobile,
}}
/>
<FlaggedFeature flag={FEATURE_FLAGS.WEB_ANALYTICS}>
<PageButton
icon={<IconWeb />}
identifier={Scene.WebAnalytics}
to={urls.webAnalytics()}
highlight="alpha"
/>
</FlaggedFeature>
<PageButton icon={<IconRecording />} identifier={Scene.Replay} to={urls.replay()} />

<div className="SideBar__heading">Feature Management</div>
Expand All @@ -200,15 +208,6 @@ function Pages(): JSX.Element {
to={urls.surveys()}
highlight="beta"
/>

<FlaggedFeature flag={FEATURE_FLAGS.WEB_ANALYTICS}>
<PageButton
icon={<IconWeb />}
identifier={Scene.WebAnalytics}
to={urls.webAnalytics()}
highlight="alpha"
/>
</FlaggedFeature>
<div className="SideBar__heading">Data</div>

<PageButton
Expand Down
48 changes: 48 additions & 0 deletions frontend/src/lib/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1603,6 +1603,54 @@ export function isNotNil<T>(arg: T): arg is Exclude<T, null | undefined> {
return arg !== null && arg !== undefined
}

/** An error signaling that a value of type `never` in TypeScript was used unexpectedly at runtime.
*
* Useful for type-narrowing, will give a compile-time error if the type of x is not `never`.
* See the example below where it catches a missing branch at compile-time.
*
* @example
*
* enum MyEnum {
* a,
* b,
* }
*
* function handleEnum(x: MyEnum) {
* switch (x) {
* case MyEnum.a:
* return
* // missing branch
* default:
* throw new UnexpectedNeverError(x) // TS2345: Argument of type MyEnum is not assignable to parameter of type never
* }
* }
*
* function handleEnum(x: MyEnum) {
* switch (x) {
* case MyEnum.a:
* return
* case MyEnum.b:
* return
* default:
* throw new UnexpectedNeverError(x) // no type error
* }
* }
*
*/
export class UnexpectedNeverError extends Error {
constructor(x: never, message?: string) {
message = message ?? 'Unexpected never: ' + String(x)
super(message)

// restore prototype chain, which is broken by Error
// see https://stackoverflow.com/questions/41102060/typescript-extending-error-class
const actualProto = new.target.prototype
if (Object.setPrototypeOf) {
Object.setPrototypeOf(this, actualProto)
}
}
}

export function calculateDays(timeValue: number, timeUnit: TimeUnitType): number {
if (timeUnit === TimeUnitType.Year) {
return timeValue * 365
Expand Down
10 changes: 2 additions & 8 deletions frontend/src/queries/nodes/DataTable/queryFeatures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import {
isPersonsNode,
isPersonsQuery,
isWebOverviewStatsQuery,
isWebStatsTableQuery,
isWebTopClicksQuery,
isWebTopPagesQuery,
isWebTopSourcesQuery,
} from '~/queries/utils'
import { Node } from '~/queries/schema'

Expand Down Expand Up @@ -55,12 +54,7 @@ export function getQueryFeatures(query: Node): Set<QueryFeature> {
}
}

if (
isWebOverviewStatsQuery(query) ||
isWebTopSourcesQuery(query) ||
isWebTopPagesQuery(query) ||
isWebTopClicksQuery(query)
) {
if (isWebOverviewStatsQuery(query) || isWebTopClicksQuery(query) || isWebStatsTableQuery(query)) {
features.add(QueryFeature.columnsInResponse)
features.add(QueryFeature.resultIsArrayOfArrays)
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/queries/nodes/DataTable/renderColumn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ export function renderColumn(
} else if (key.startsWith('context.columns.')) {
const columnName = trimQuotes(key.substring(16)) // 16 = "context.columns.".length
const Component = context?.columns?.[columnName]?.render
return Component ? <Component record={record} columnName={columnName} value={value} /> : ''
return Component ? <Component record={record} columnName={columnName} value={value} query={query} /> : ''
} else if (key === 'id' && (isPersonsNode(query.source) || isPersonsQuery(query.source))) {
return (
<CopyToClipboardInline
Expand Down
8 changes: 7 additions & 1 deletion frontend/src/queries/nodes/DataTable/renderColumnMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ export function renderColumnMeta(key: string, query: DataTableNode, context?: Qu
title = <PropertyKeyInfo value={trimQuotes(key.substring(11))} type={PropertyFilterType.Event} disableIcon />
} else if (key.startsWith('context.columns.')) {
const column = trimQuotes(key.substring(16))
title = context?.columns?.[column]?.title ?? column.replace('_', ' ')
const queryContextColumn = context?.columns?.[column]
const Component = queryContextColumn?.renderTitle
title = Component ? (
<Component columnName={column} query={query} />
) : (
queryContextColumn?.title ?? column.replace('_', ' ')
)
} else if (key === 'person.$delete') {
title = ''
width = 0
Expand Down
106 changes: 33 additions & 73 deletions frontend/src/queries/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,13 +103,10 @@
"$ref": "#/definitions/WebOverviewStatsQuery"
},
{
"$ref": "#/definitions/WebTopSourcesQuery"
"$ref": "#/definitions/WebStatsTableQuery"
},
{
"$ref": "#/definitions/WebTopClicksQuery"
},
{
"$ref": "#/definitions/WebTopPagesQuery"
}
]
},
Expand Down Expand Up @@ -412,13 +409,10 @@
"$ref": "#/definitions/WebOverviewStatsQuery"
},
{
"$ref": "#/definitions/WebTopSourcesQuery"
"$ref": "#/definitions/WebStatsTableQuery"
},
{
"$ref": "#/definitions/WebTopClicksQuery"
},
{
"$ref": "#/definitions/WebTopPagesQuery"
}
],
"description": "Source of the events"
Expand Down Expand Up @@ -2413,7 +2407,14 @@
},
"WebAnalyticsPropertyFilters": {
"items": {
"$ref": "#/definitions/EventPropertyFilter"
"anyOf": [
{
"$ref": "#/definitions/EventPropertyFilter"
},
{
"$ref": "#/definitions/HogQLPropertyFilter"
}
]
},
"type": "array"
},
Expand Down Expand Up @@ -2474,84 +2475,43 @@
"required": ["results"],
"type": "object"
},
"WebTopClicksQuery": {
"additionalProperties": false,
"properties": {
"dateRange": {
"$ref": "#/definitions/DateRange"
},
"kind": {
"const": "WebTopClicksQuery",
"type": "string"
},
"properties": {
"$ref": "#/definitions/WebAnalyticsPropertyFilters"
},
"response": {
"$ref": "#/definitions/WebTopClicksQueryResponse"
}
},
"required": ["kind", "properties"],
"type": "object"
"WebStatsBreakdown": {
"enum": [
"Page",
"InitialPage",
"InitialReferringDomain",
"InitialUTMSource",
"InitialUTMCampaign",
"Browser",
"OS",
"DeviceType"
],
"type": "string"
},
"WebTopClicksQueryResponse": {
"WebStatsTableQuery": {
"additionalProperties": false,
"properties": {
"columns": {
"items": {},
"type": "array"
},
"hogql": {
"type": "string"
"breakdownBy": {
"$ref": "#/definitions/WebStatsBreakdown"
},
"is_cached": {
"type": "boolean"
},
"last_refresh": {
"type": "string"
},
"next_allowed_client_refresh": {
"type": "string"
},
"results": {
"items": {},
"type": "array"
},
"timings": {
"items": {
"$ref": "#/definitions/QueryTiming"
},
"type": "array"
},
"types": {
"items": {},
"type": "array"
}
},
"required": ["results"],
"type": "object"
},
"WebTopPagesQuery": {
"additionalProperties": false,
"properties": {
"dateRange": {
"$ref": "#/definitions/DateRange"
},
"kind": {
"const": "WebTopPagesQuery",
"const": "WebStatsTableQuery",
"type": "string"
},
"properties": {
"$ref": "#/definitions/WebAnalyticsPropertyFilters"
},
"response": {
"$ref": "#/definitions/WebTopPagesQueryResponse"
"$ref": "#/definitions/WebStatsTableQueryResponse"
}
},
"required": ["kind", "properties"],
"required": ["kind", "properties", "breakdownBy"],
"type": "object"
},
"WebTopPagesQueryResponse": {
"WebStatsTableQueryResponse": {
"additionalProperties": false,
"properties": {
"columns": {
Expand Down Expand Up @@ -2588,27 +2548,27 @@
"required": ["results"],
"type": "object"
},
"WebTopSourcesQuery": {
"WebTopClicksQuery": {
"additionalProperties": false,
"properties": {
"dateRange": {
"$ref": "#/definitions/DateRange"
},
"kind": {
"const": "WebTopSourcesQuery",
"const": "WebTopClicksQuery",
"type": "string"
},
"properties": {
"$ref": "#/definitions/WebAnalyticsPropertyFilters"
},
"response": {
"$ref": "#/definitions/WebTopSourcesQueryResponse"
"$ref": "#/definitions/WebTopClicksQueryResponse"
}
},
"required": ["kind", "properties"],
"type": "object"
},
"WebTopSourcesQueryResponse": {
"WebTopClicksQueryResponse": {
"additionalProperties": false,
"properties": {
"columns": {
Expand Down
Loading
Loading