diff --git a/src/app/(main)/boards/boardComponentRegistry.tsx b/src/app/(main)/boards/boardComponentRegistry.tsx
index 2af1c7006..2c717bee0 100644
--- a/src/app/(main)/boards/boardComponentRegistry.tsx
+++ b/src/app/(main)/boards/boardComponentRegistry.tsx
@@ -49,6 +49,7 @@ export const CATEGORIES = [
const METRIC_TYPES = [
{ label: 'Path', value: 'path' },
+ { label: 'URL', value: 'fullPath' },
{ label: 'Entry page', value: 'entry' },
{ label: 'Exit page', value: 'exit' },
{ label: 'Title', value: 'title' },
diff --git a/src/app/(main)/links/[linkId]/LinkPage.tsx b/src/app/(main)/links/[linkId]/LinkPage.tsx
index 5d10fa82b..910d1f51a 100644
--- a/src/app/(main)/links/[linkId]/LinkPage.tsx
+++ b/src/app/(main)/links/[linkId]/LinkPage.tsx
@@ -10,7 +10,7 @@ import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { PageBody } from '@/components/common/PageBody';
import { Panel } from '@/components/common/Panel';
-const excludedIds = ['path', 'entry', 'exit', 'title', 'language', 'screen', 'event'];
+const excludedIds = ['path', 'fullPath', 'entry', 'exit', 'title', 'language', 'screen', 'event'];
export function LinkPage({
linkId,
diff --git a/src/app/(main)/pixels/[pixelId]/PixelPage.tsx b/src/app/(main)/pixels/[pixelId]/PixelPage.tsx
index e8d605d24..09d6ce4e2 100644
--- a/src/app/(main)/pixels/[pixelId]/PixelPage.tsx
+++ b/src/app/(main)/pixels/[pixelId]/PixelPage.tsx
@@ -10,7 +10,7 @@ import { WebsiteChart } from '@/app/(main)/websites/[websiteId]/WebsiteChart';
import { PageBody } from '@/components/common/PageBody';
import { Panel } from '@/components/common/Panel';
-const excludedIds = ['path', 'entry', 'exit', 'title', 'language', 'screen', 'event'];
+const excludedIds = ['path', 'fullPath', 'entry', 'exit', 'title', 'language', 'screen', 'event'];
export function PixelPage({
pixelId,
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx
index c49eaa02f..e3c333693 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedMenu.tsx
@@ -25,6 +25,7 @@ import {
Tag,
Target,
Type,
+ Waypoints,
} from '@/components/icons';
import { Lightning } from '@/components/svg';
@@ -45,7 +46,7 @@ export function WebsiteExpandedMenu({
const items = [
{
- label: 'URL',
+ label: t(labels.pages),
items: [
{
id: 'path',
@@ -53,6 +54,12 @@ export function WebsiteExpandedMenu({
path: updateParams({ view: 'path' }),
icon: ,
},
+ {
+ id: 'fullPath',
+ label: t(labels.url),
+ path: updateParams({ view: 'fullPath' }),
+ icon: ,
+ },
{
id: 'entry',
label: t(labels.entry),
diff --git a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
index 71fbdc703..ebe8d976c 100644
--- a/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsiteExpandedView.tsx
@@ -17,6 +17,7 @@ export function WebsiteExpandedView({
const {
query: { view },
} = useNavigation();
+ const title = view === 'fullPath' ? t(labels.url) : t(labels[view]);
return (
@@ -44,12 +45,7 @@ export function WebsiteExpandedView({
-
+
diff --git a/src/app/(main)/websites/[websiteId]/WebsitePanels.tsx b/src/app/(main)/websites/[websiteId]/WebsitePanels.tsx
index 7d5d08c8c..f19a7b400 100644
--- a/src/app/(main)/websites/[websiteId]/WebsitePanels.tsx
+++ b/src/app/(main)/websites/[websiteId]/WebsitePanels.tsx
@@ -26,12 +26,16 @@ export function WebsitePanels({ websiteId }: { websiteId: string }) {
{t(labels.path)}
+ {t(labels.url)}
{t(labels.entry)}
{t(labels.exit)}
+
+
+
diff --git a/src/components/metrics/MetricLabel.tsx b/src/components/metrics/MetricLabel.tsx
index dae5dbabf..21618b90d 100644
--- a/src/components/metrics/MetricLabel.tsx
+++ b/src/components/metrics/MetricLabel.tsx
@@ -94,6 +94,9 @@ export function MetricLabel({ type, data }: MetricLabelProps) {
/>
);
+ case 'fullPath':
+ return label || `(${t(labels.none)})`;
+
case 'device':
return (
{
const { type, limit = 500, offset = 0 } = parameters;
- let column = FILTER_COLUMNS[type] || type;
+ let column = getPageviewColumn(type);
const { rawQuery, parseFilters, getTimestampDiffSQL } = prisma;
const { filterQuery, joinSessionQuery, cohortQuery, excludeBounceQuery, queryParams } =
parseFilters(
@@ -49,8 +49,6 @@ async function relationalQuery(
let entryExitQuery = '';
let excludeDomain = '';
- const isPathType = type === 'path' || type === 'entry' || type === 'exit';
-
if (column === 'referrer_domain') {
excludeDomain = `and website_event.referrer_domain != regexp_replace(website_event.hostname, '^www.', '')
and website_event.referrer_domain != ''`;
@@ -77,11 +75,11 @@ async function relationalQuery(
`;
}
- const selectColumn = isPathType
+ const selectColumn = type === 'fullPath'
? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end`
: column;
- const groupByColumn = isPathType
+ const groupByColumn = type === 'fullPath'
? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end`
: column;
@@ -131,7 +129,7 @@ async function clickhouseQuery(
filters: QueryFilters,
): Promise<{ x: string; y: number }[]> {
const { type, limit = 500, offset = 0 } = parameters;
- let column = FILTER_COLUMNS[type] || type;
+ let column = getPageviewColumn(type);
const { rawQuery, parseFilters } = clickhouse;
const { filterQuery, cohortQuery, excludeBounceQuery, queryParams } = parseFilters({
...filters,
@@ -140,7 +138,6 @@ async function clickhouseQuery(
let excludeDomain = '';
let entryExitQuery = '';
- const isPathType = type === 'path' || type === 'entry' || type === 'exit';
let selectColumn = column;
if (column === 'referrer_domain') {
@@ -165,8 +162,8 @@ async function clickhouseQuery(
group by visit_id) x
ON x.visit_id = website_event.visit_id`;
- selectColumn = `if(x.url_query != '', concat(x.url_path, '?', x.url_query), x.url_path)`;
- } else if (isPathType) {
+ selectColumn = `x.url_path`;
+ } else if (type === 'fullPath') {
selectColumn = `if(url_query != '', concat(url_path, '?', url_query), url_path)`;
}
@@ -244,3 +241,11 @@ export function toPostgresGroupedReferrer(
function toPostgresLikeClause(column: string, arr: string[]) {
return arr.map(val => `${column} ilike '%${val.replace(/'/g, "''")}%'`).join(' OR\n ');
}
+
+function getPageviewColumn(type: string) {
+ if (type === 'fullPath') {
+ return 'url_path';
+ }
+
+ return FILTER_COLUMNS[type] || type;
+}
diff --git a/src/queries/sql/pageviews/getPageviewMetrics.ts b/src/queries/sql/pageviews/getPageviewMetrics.ts
index 9d6120bed..cfc8d0c7f 100644
--- a/src/queries/sql/pageviews/getPageviewMetrics.ts
+++ b/src/queries/sql/pageviews/getPageviewMetrics.ts
@@ -32,7 +32,7 @@ async function relationalQuery(
filters: QueryFilters,
): Promise {
const { type, limit = 500, offset = 0 } = parameters;
- let column = FILTER_COLUMNS[type] || type;
+ let column = getPageviewColumn(type);
const { rawQuery, parseFilters } = prisma;
const { filterQuery, joinSessionQuery, cohortQuery, excludeBounceQuery, queryParams } =
parseFilters(
@@ -45,8 +45,6 @@ async function relationalQuery(
let entryExitQuery = '';
let excludeDomain = '';
- const isPathType = type === 'path' || type === 'entry' || type === 'exit';
-
if (column === 'referrer_domain') {
excludeDomain = `and website_event.referrer_domain != regexp_replace(website_event.hostname, '^www.', '')
and website_event.referrer_domain != ''`;
@@ -70,12 +68,10 @@ async function relationalQuery(
on x.visit_id = website_event.visit_id
`;
- column = isPathType
- ? `case when x.url_query != '' then x.url_path || '?' || x.url_query else x.url_path end`
- : `x.${FILTER_COLUMNS[type] || type}`;
+ column = `x.${FILTER_COLUMNS[type] || type}`;
}
- const selectColumn = isPathType && type !== 'entry' && type !== 'exit'
+ const selectColumn = type === 'fullPath'
? `case when website_event.url_query != '' then website_event.url_path || '?' || website_event.url_query else website_event.url_path end`
: column;
@@ -110,7 +106,7 @@ async function clickhouseQuery(
filters: QueryFilters,
): Promise<{ x: string; y: number }[]> {
const { type, limit = 500, offset = 0 } = parameters;
- let column = FILTER_COLUMNS[type] || type;
+ let column = getPageviewColumn(type);
const { rawQuery, parseFilters } = clickhouse;
const { filterQuery, cohortQuery, excludeBounceQuery, queryParams } = parseFilters({
...filters,
@@ -119,9 +115,7 @@ async function clickhouseQuery(
let sql = '';
let excludeDomain = '';
- const isPathType = type === 'path' || type === 'entry' || type === 'exit';
-
- if (EVENT_COLUMNS.some(item => Object.keys(filters).includes(item))) {
+ if (type === 'fullPath' || EVENT_COLUMNS.some(item => Object.keys(filters).includes(item))) {
let entryExitQuery = '';
let selectColumn = column;
@@ -143,8 +137,9 @@ async function clickhouseQuery(
group by visit_id) x
ON x.visit_id = website_event.visit_id`;
- selectColumn = `if(x.url_query != '', concat(x.url_path, '?', x.url_query), x.url_path)`;
- } else if (isPathType) {
+ column = `x.url_path`;
+ selectColumn = `x.url_path`;
+ } else if (type === 'fullPath') {
selectColumn = `if(url_query != '', concat(url_path, '?', url_query), url_path)`;
}
@@ -210,3 +205,11 @@ async function clickhouseQuery(
return rawQuery(sql, { ...queryParams, ...parameters }, FUNCTION_NAME);
}
+
+function getPageviewColumn(type: string) {
+ if (type === 'fullPath') {
+ return 'url_path';
+ }
+
+ return FILTER_COLUMNS[type] || type;
+}