mirror of
https://github.com/umami-software/umami.git
synced 2026-05-30 06:47:25 +00:00
update session replay tracking code UI/UX
This commit is contained in:
@@ -255,6 +255,7 @@
|
||||
"play": "Play",
|
||||
"replay": "Replay",
|
||||
"replay-id": "Replay ID",
|
||||
"replay-code": "Session replay code",
|
||||
"replay-enabled": "Replay enabled",
|
||||
"replays": "Replays",
|
||||
"reports": "Reports",
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
Select,
|
||||
Slider,
|
||||
Switch,
|
||||
Text,
|
||||
TextField,
|
||||
} from '@umami/react-zen';
|
||||
import { useState } from 'react';
|
||||
@@ -14,6 +15,8 @@ import { EmptyPlaceholder } from '@/components/common/EmptyPlaceholder';
|
||||
import { useMessages, useSubscription, useUpdateQuery, useWebsite } from '@/components/hooks';
|
||||
import { Video } from '@/components/icons';
|
||||
|
||||
const RECORDER_NAME = 'recorder.js';
|
||||
|
||||
interface ReplayConfig {
|
||||
sampleRate?: number;
|
||||
maskLevel?: string;
|
||||
@@ -35,6 +38,14 @@ export function WebsiteReplaySettings({ websiteId }: { websiteId: string }) {
|
||||
const [maxDuration, setMaxDuration] = useState(String(config.maxDuration ?? 300000));
|
||||
const [blockSelector, setBlockSelector] = useState(config.blockSelector ?? '');
|
||||
|
||||
const recorderUrl = cloudMode
|
||||
? `${process.env.cloudUrl}/${RECORDER_NAME}`
|
||||
: `${window?.location?.origin || ''}${process.env.basePath || ''}/${RECORDER_NAME}`;
|
||||
|
||||
let recorderAttrs = `data-website-id="${websiteId}" data-sample-rate="${sampleRate}" data-mask-level="${maskLevel}" data-max-duration="${parseInt(maxDuration, 10) || 300000}"`;
|
||||
if (blockSelector) recorderAttrs += ` data-block-selector="${blockSelector}"`;
|
||||
const recorderCode = `<script defer src="${recorderUrl}" ${recorderAttrs}></script>`;
|
||||
|
||||
const handleToggle = async (value: boolean) => {
|
||||
const previous = enabled;
|
||||
setEnabled(value);
|
||||
@@ -106,6 +117,9 @@ export function WebsiteReplaySettings({ websiteId }: { websiteId: string }) {
|
||||
</Switch>
|
||||
{enabled && (
|
||||
<>
|
||||
<Label>{t(labels.replayCode)}</Label>
|
||||
<Text color="muted">{t(messages.trackingCode)}</Text>
|
||||
<TextField value={recorderCode} isReadOnly allowCopy asTextArea resize="none" className="code-textarea" />
|
||||
<Slider
|
||||
label={t(labels.sampleRate)}
|
||||
minValue={0.05}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Column, Label, Text, TextField } from '@umami/react-zen';
|
||||
import { useConfig, useMessages, useWebsite } from '@/components/hooks';
|
||||
import { useConfig, useMessages } from '@/components/hooks';
|
||||
|
||||
const SCRIPT_NAME = 'script.js';
|
||||
const RECORDER_NAME = 'recorder.js';
|
||||
|
||||
export function WebsiteTrackingCode({
|
||||
websiteId,
|
||||
@@ -13,7 +12,6 @@ export function WebsiteTrackingCode({
|
||||
}) {
|
||||
const { t, messages, labels } = useMessages();
|
||||
const config = useConfig();
|
||||
const website = useWebsite();
|
||||
|
||||
const trackerScriptName =
|
||||
config?.trackerScriptName?.split(',')?.map((n: string) => n.trim())?.[0] || SCRIPT_NAME;
|
||||
@@ -30,27 +28,13 @@ export function WebsiteTrackingCode({
|
||||
|
||||
const url = trackerScriptName?.startsWith('http') ? trackerScriptName : getUrl(trackerScriptName);
|
||||
|
||||
let code = `<script defer src="${url}" data-website-id="${websiteId}"></script>`;
|
||||
|
||||
if (website?.replayEnabled) {
|
||||
const recorderUrl = getUrl(RECORDER_NAME);
|
||||
const replayConfig = (website.replayConfig as any) || {};
|
||||
let recorderAttrs = `data-website-id="${websiteId}"`;
|
||||
if (replayConfig.sampleRate !== undefined)
|
||||
recorderAttrs += ` data-sample-rate="${replayConfig.sampleRate}"`;
|
||||
if (replayConfig.maskLevel) recorderAttrs += ` data-mask-level="${replayConfig.maskLevel}"`;
|
||||
if (replayConfig.maxDuration !== undefined)
|
||||
recorderAttrs += ` data-max-duration="${replayConfig.maxDuration}"`;
|
||||
if (replayConfig.blockSelector)
|
||||
recorderAttrs += ` data-block-selector="${replayConfig.blockSelector}"`;
|
||||
code += `\n<script defer src="${recorderUrl}" ${recorderAttrs}></script>`;
|
||||
}
|
||||
const code = `<script defer src="${url}" data-website-id="${websiteId}"></script>`;
|
||||
|
||||
return (
|
||||
<Column gap>
|
||||
<Label>{t(labels.trackingCode)}</Label>
|
||||
<Text color="muted">{t(messages.trackingCode)}</Text>
|
||||
<TextField value={code} isReadOnly allowCopy asTextArea resize="none" />
|
||||
<TextField value={code} isReadOnly allowCopy asTextArea resize="none" className="code-textarea" />
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ select:-webkit-autofill:focus {
|
||||
transition: color 5000s ease-in-out 0s;
|
||||
}
|
||||
|
||||
/* Code snippet textareas */
|
||||
.code-textarea textarea {
|
||||
min-height: 100px;
|
||||
}
|
||||
|
||||
/* rrweb-player overrides */
|
||||
.rr-controller__btns {
|
||||
gap: 8px;
|
||||
|
||||
@@ -371,6 +371,7 @@ export const labels: Record<string, string> = {
|
||||
replay: 'label.replay',
|
||||
replayId: 'label.replay-id',
|
||||
replayEnabled: 'label.replay-enabled',
|
||||
replayCode: 'label.replay-code',
|
||||
sampleRate: 'label.sample-rate',
|
||||
maskLevel: 'label.mask-level',
|
||||
maxDuration: 'label.max-duration',
|
||||
|
||||
Reference in New Issue
Block a user