Skip to content

Commit 4ad71de

Browse files
feat: add UTM dimensions to ui
Signed-off-by: Henry Gressmann <[email protected]>
1 parent b4ae509 commit 4ad71de

File tree

6 files changed

+133
-5
lines changed

6 files changed

+133
-5
lines changed

data/licenses-cargo.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

data/licenses-npm.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

web/src/components/dimensions/dimensions.module.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@
1010
display: flex;
1111
gap: 1rem;
1212
margin-bottom: 1rem;
13+
14+
.dimensionSelect {
15+
all: unset;
16+
user-select: none;
17+
appearance: menulist;
18+
cursor: pointer;
19+
margin-right: auto;
20+
outline: none;
21+
padding-bottom: 0.2rem;
22+
padding-left: 0.2rem;
23+
box-shadow: none !important;
24+
}
1325
}
1426

1527
.tabsList > button {

web/src/components/dimensions/index.tsx

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as Tabs from "@radix-ui/react-tabs";
2-
import { LinkIcon, SquareArrowOutUpRightIcon } from "lucide-react";
2+
import { ArrowDownIcon, LinkIcon, PinIcon, SquareArrowOutUpRightIcon } from "lucide-react";
33
import styles from "./dimensions.module.css";
44

55
import { type Dimension, type DimensionTableRow, dimensionNames, metricNames, useDimension } from "../../api";
@@ -9,6 +9,7 @@ import { cls, countryCodeToFlag, formatHost, formatPath, getHref, tryParseUrl }
99
import { DetailsModal } from "./modal";
1010
import { formatMetricVal } from "../../utils";
1111
import type { ProjectQuery } from "../project";
12+
import { useState } from "react";
1213

1314
export const cardStyles = styles.card;
1415

@@ -46,6 +47,67 @@ export const DimensionTabsCard = ({
4647
);
4748
};
4849

50+
export const DimensionDropdownCard = ({
51+
dimensions,
52+
query,
53+
onSelect,
54+
}: {
55+
dimensions: Dimension[];
56+
query: ProjectQuery;
57+
onSelect: (value: DimensionTableRow, dimension: Dimension) => void;
58+
}) => {
59+
return (
60+
<article className={styles.card}>
61+
<DimensionDropdown dimensions={dimensions} query={query} onSelect={onSelect} />
62+
</article>
63+
);
64+
};
65+
66+
export const DimensionDropdown = ({
67+
dimensions,
68+
query,
69+
onSelect,
70+
}: {
71+
dimensions: Dimension[];
72+
query: ProjectQuery;
73+
onSelect: (value: DimensionTableRow, dimension: Dimension) => void;
74+
}) => {
75+
const [selectedDimension, setSelectedDimension] = useState(dimensions[0]);
76+
77+
return (
78+
<Tabs.Root
79+
className={styles.tabs}
80+
value={selectedDimension}
81+
onValueChange={(value) => setSelectedDimension(value as Dimension)}
82+
>
83+
<Tabs.List className={styles.tabsList}>
84+
<select
85+
className={styles.dimensionSelect}
86+
value={selectedDimension}
87+
onChange={(e) => setSelectedDimension(e.target.value as Dimension)}
88+
>
89+
{dimensions.map((dimension) => (
90+
<option key={dimension} value={dimension}>
91+
{dimensionNames[dimension]}
92+
</option>
93+
))}
94+
</select>
95+
{/* {Object.entries(dimensions).map(([key, value]) => (
96+
<Tabs.Trigger key={key} value={value}>
97+
{dimensionNames[value]}
98+
</Tabs.Trigger>
99+
))} */}
100+
<div>{metricNames[query.metric]}</div>
101+
</Tabs.List>
102+
{dimensions.map((dimension) => (
103+
<Tabs.Content key={dimension} value={dimension} className={styles.tabsContent}>
104+
<DimensionTable dimension={dimension} query={query} onSelect={(value) => onSelect(value, dimension)} />
105+
</Tabs.Content>
106+
))}
107+
</Tabs.Root>
108+
);
109+
};
110+
49111
export const DimensionTabs = ({
50112
dimensions,
51113
query,
@@ -125,6 +187,36 @@ const DimensionValueButton = ({
125187
);
126188

127189
const dimensionLabels: Record<Dimension, (value: DimensionTableRow, onSelect: () => void) => React.ReactNode> = {
190+
utm_campaign: (value, onSelect) => (
191+
<>
192+
<PinIcon size={24} />
193+
<DimensionValueButton onSelect={onSelect}>{value.dimensionValue || "Unknown/None"}</DimensionValueButton>
194+
</>
195+
),
196+
utm_content: (value, onSelect) => (
197+
<>
198+
<PinIcon size={24} />
199+
<DimensionValueButton onSelect={onSelect}>{value.dimensionValue || "Unknown/None"}</DimensionValueButton>
200+
</>
201+
),
202+
utm_medium: (value, onSelect) => (
203+
<>
204+
<PinIcon size={24} />
205+
<DimensionValueButton onSelect={onSelect}>{value.dimensionValue || "Unknown/None"}</DimensionValueButton>
206+
</>
207+
),
208+
utm_source: (value, onSelect) => (
209+
<>
210+
<PinIcon size={24} />
211+
<DimensionValueButton onSelect={onSelect}>{value.dimensionValue || "Unknown/None"}</DimensionValueButton>
212+
</>
213+
),
214+
utm_term: (value, onSelect) => (
215+
<>
216+
<PinIcon size={24} />
217+
<DimensionValueButton onSelect={onSelect}>{value.dimensionValue || "Unknown/None"}</DimensionValueButton>
218+
</>
219+
),
128220
platform: (value, onSelect) => (
129221
<>
130222
<OSIcon os={value.dimensionValue} size={24} />

web/src/components/project.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { SelectRange } from "./project/range";
1414
import { ProjectHeader } from "./project/project";
1515
import { SelectMetrics } from "./project/metric";
1616
import { SelectFilters } from "./project/filter";
17-
import { DimensionCard, DimensionTabs, DimensionTabsCard, cardStyles } from "./dimensions";
17+
import { DimensionCard, DimensionDropdownCard, DimensionTabs, DimensionTabsCard, cardStyles } from "./dimensions";
1818

1919
const WorldMap = lazy(() => import("./worldmap").then((module) => ({ default: module.WorldMap })));
2020

@@ -102,7 +102,11 @@ export const Project = () => {
102102
</article>
103103
<div className={styles.tables}>
104104
<DimensionTabsCard dimensions={["url", "fqdn"]} query={query} onSelect={onSelectDimRow} />
105-
<DimensionCard dimension={"referrer"} query={query} onSelect={(v) => onSelectDimRow(v, "referrer")} />
105+
<DimensionDropdownCard
106+
dimensions={["referrer", "utm_source", "utm_medium", "utm_campaign", "utm_content", "utm_term"]}
107+
query={query}
108+
onSelect={onSelectDimRow}
109+
/>
106110
<GeoCard query={query} onSelect={onSelectDimRow} />
107111
<DimensionTabsCard dimensions={["platform", "browser"]} query={query} onSelect={onSelectDimRow} />
108112
<DimensionCard dimension={"mobile"} query={query} onSelect={(v) => onSelectDimRow(v, "mobile")} />

web/src/components/project/filter.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,26 @@ const filters = {
7575
invertable: true,
7676
filterTypes: ["equal", "contains"],
7777
},
78+
utm_campaign: {
79+
invertable: true,
80+
filterTypes: ["equal", "contains"],
81+
},
82+
utm_content: {
83+
invertable: true,
84+
filterTypes: ["equal", "contains"],
85+
},
86+
utm_medium: {
87+
invertable: true,
88+
filterTypes: ["equal", "contains"],
89+
},
90+
utm_source: {
91+
invertable: true,
92+
filterTypes: ["equal", "contains"],
93+
},
94+
utm_term: {
95+
invertable: true,
96+
filterTypes: ["equal", "contains"],
97+
},
7898
mobile: {
7999
custom: true,
80100
displayValue: (filter: DimensionFilter) => (filter.filterType === "is_true" ? "Mobile" : "Desktop"),

0 commit comments

Comments
 (0)