mirror of
https://github.com/kremalicious/umami.git
synced 2025-01-11 13:44:01 +01:00
Updated test console. Refactored fetch for tracker.
This commit is contained in:
commit
bc75b622b5
@ -1,4 +1,3 @@
|
||||
import React, { useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Head from 'next/head';
|
||||
import Link from 'next/link';
|
||||
@ -9,36 +8,37 @@ import DropDown from 'components/common/DropDown';
|
||||
import WebsiteChart from 'components/metrics/WebsiteChart';
|
||||
import EventsChart from 'components/metrics/EventsChart';
|
||||
import Button from 'components/common/Button';
|
||||
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||
import Icon from 'components/common/Icon';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import useUser from 'hooks/useUser';
|
||||
import ChevronDown from 'assets/chevron-down.svg';
|
||||
import styles from './TestConsole.module.css';
|
||||
|
||||
export default function TestConsole() {
|
||||
const { user } = useUser();
|
||||
const [website, setWebsite] = useState();
|
||||
const [show, setShow] = useState(true);
|
||||
const { basePath } = useRouter();
|
||||
const { data } = useFetch('/websites');
|
||||
const router = useRouter();
|
||||
const {
|
||||
basePath,
|
||||
query: { id },
|
||||
} = router;
|
||||
const websiteId = id?.[0];
|
||||
|
||||
if (!data || !user?.is_admin) {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const options = data.map(({ name, website_id }) => ({ label: name, value: website_id }));
|
||||
const website = data.find(({ website_id }) => website_id === +websiteId);
|
||||
const selectedValue = options.find(({ value }) => value === website?.website_id)?.value;
|
||||
|
||||
console.log({ websiteId, data, options, website });
|
||||
|
||||
function handleSelect(value) {
|
||||
setWebsite(data.find(({ website_id }) => website_id === value));
|
||||
router.push(`/console/${value}`);
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
window.umami('event (default)');
|
||||
window.umami('umami-default');
|
||||
window.umami.trackView('/page-view', 'https://www.google.com');
|
||||
window.umami.trackEvent('event (custom)', null, 'custom-type');
|
||||
window.umami.trackEvent('event (custom)', { test: 'test-data' }, 'custom-data-type');
|
||||
window.umami.trackEvent('track-event-no-data');
|
||||
window.umami.trackEvent('track-event-with-data', { test: 'test-data', time: Date.now() });
|
||||
}
|
||||
|
||||
return (
|
||||
@ -62,43 +62,37 @@ export default function TestConsole() {
|
||||
onChange={handleSelect}
|
||||
/>
|
||||
</PageHeader>
|
||||
{!selectedValue && <EmptyPlaceholder msg="I hope you know what you're doing here" />}
|
||||
{selectedValue && (
|
||||
{website && (
|
||||
<>
|
||||
<div>
|
||||
<Icon
|
||||
icon={<ChevronDown />}
|
||||
className={classNames({ [styles.hidden]: !show })}
|
||||
onClick={() => setShow(!show)}
|
||||
/>
|
||||
</div>
|
||||
{show && (
|
||||
<div className={classNames(styles.test, 'row')}>
|
||||
<div className="col-4">
|
||||
<PageHeader>Page links</PageHeader>
|
||||
<div>
|
||||
<Link href={`?page=1`}>
|
||||
<Link href={`/console/${websiteId}?page=1`}>
|
||||
<a>page one</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={`?page=2`}>
|
||||
<Link href={`/console/${websiteId}?page=2`}>
|
||||
<a>page two</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={`https://www.google.com`}>
|
||||
<a className="umami--click--external-link">external link</a>
|
||||
<a className="umami--click--external-link-direct">external link (direct)</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={`https://www.google.com`}>
|
||||
<a className="umami--click--external-link-tab" target="_blank">
|
||||
external link (tab)
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-4">
|
||||
<PageHeader>CSS events</PageHeader>
|
||||
<Button
|
||||
id="primary-button"
|
||||
className="umami--click--primary-button"
|
||||
variant="action"
|
||||
>
|
||||
<Button id="primary-button" className="umami--click--button-click" variant="action">
|
||||
Send event
|
||||
</Button>
|
||||
</div>
|
||||
@ -109,7 +103,6 @@ export default function TestConsole() {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<WebsiteChart
|
||||
|
@ -35,6 +35,7 @@ if (process.env.FORCE_SSL) {
|
||||
module.exports = {
|
||||
env: {
|
||||
currentVersion: pkg.version,
|
||||
isProduction: process.env.NODE_ENV === 'production',
|
||||
},
|
||||
basePath: process.env.BASE_PATH,
|
||||
output: 'standalone',
|
||||
|
@ -2,11 +2,13 @@ import React from 'react';
|
||||
import Layout from 'components/layout/Layout';
|
||||
import TestConsole from 'components/pages/TestConsole';
|
||||
import useRequireLogin from 'hooks/useRequireLogin';
|
||||
import useUser from 'hooks/useUser';
|
||||
|
||||
export default function TestPage() {
|
||||
export default function ConsolePage({ enabled }) {
|
||||
const { loading } = useRequireLogin();
|
||||
const { user } = useUser();
|
||||
|
||||
if (loading) {
|
||||
if (loading || !enabled || !user?.is_admin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -16,3 +18,9 @@ export default function TestPage() {
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: { enabled: !!process.env.ENABLE_TEST_CONSOLE },
|
||||
};
|
||||
}
|
108
tracker/index.js
108
tracker/index.js
@ -5,23 +5,25 @@ import { removeTrailingSlash } from '../lib/url';
|
||||
const {
|
||||
screen: { width, height },
|
||||
navigator: { language },
|
||||
location: { hostname, pathname, search },
|
||||
location,
|
||||
localStorage,
|
||||
document,
|
||||
history,
|
||||
} = window;
|
||||
const { hostname, pathname, search } = location;
|
||||
const { currentScript } = document;
|
||||
|
||||
const script = document.querySelector('script[data-website-id]');
|
||||
if (!currentScript) return;
|
||||
|
||||
if (!script) return;
|
||||
|
||||
const attr = script.getAttribute.bind(script);
|
||||
const website = attr('data-website-id');
|
||||
const hostUrl = attr('data-host-url');
|
||||
const autoTrack = attr('data-auto-track') !== 'false';
|
||||
const dnt = attr('data-do-not-track');
|
||||
const cssEvents = attr('data-css-events') !== 'false';
|
||||
const domain = attr('data-domains') || '';
|
||||
const _data = 'data-';
|
||||
const _false = 'false';
|
||||
const attr = currentScript.getAttribute.bind(currentScript);
|
||||
const website = attr(_data + 'website-id');
|
||||
const hostUrl = attr(_data + 'host-url');
|
||||
const autoTrack = attr(_data + 'auto-track') !== _false;
|
||||
const dnt = attr(_data + 'do-not-track');
|
||||
const cssEvents = attr(_data + 'css-events') !== _false;
|
||||
const domain = attr(_data + 'domains') || '';
|
||||
const domains = domain.split(',').map(n => n.trim());
|
||||
|
||||
const eventClass = /^umami--([a-z]+)--([\w]+[\w-]*)$/;
|
||||
@ -34,7 +36,8 @@ import { removeTrailingSlash } from '../lib/url';
|
||||
|
||||
const root = hostUrl
|
||||
? removeTrailingSlash(hostUrl)
|
||||
: script.src.split('/').slice(0, -1).join('/');
|
||||
: currentScript.src.split('/').slice(0, -1).join('/');
|
||||
const endpoint = `${root}/api/collect`;
|
||||
const screen = `${width}x${height}`;
|
||||
const listeners = {};
|
||||
let currentUrl = `${pathname}${search}`;
|
||||
@ -43,21 +46,6 @@ import { removeTrailingSlash } from '../lib/url';
|
||||
|
||||
/* Collect metrics */
|
||||
|
||||
const post = (url, data, callback) => {
|
||||
const req = new XMLHttpRequest();
|
||||
req.open('POST', url, true);
|
||||
req.setRequestHeader('Content-Type', 'application/json');
|
||||
if (cache) req.setRequestHeader('x-umami-cache', cache);
|
||||
|
||||
req.onreadystatechange = () => {
|
||||
if (req.readyState === 4) {
|
||||
callback(req.response);
|
||||
}
|
||||
};
|
||||
|
||||
req.send(JSON.stringify(data));
|
||||
};
|
||||
|
||||
const getPayload = () => ({
|
||||
website,
|
||||
hostname,
|
||||
@ -68,7 +56,7 @@ import { removeTrailingSlash } from '../lib/url';
|
||||
|
||||
const assign = (a, b) => {
|
||||
Object.keys(b).forEach(key => {
|
||||
a[key] = b[key];
|
||||
if (b[key] !== undefined) a[key] = b[key];
|
||||
});
|
||||
return a;
|
||||
};
|
||||
@ -76,17 +64,16 @@ import { removeTrailingSlash } from '../lib/url';
|
||||
const collect = (type, payload) => {
|
||||
if (trackingDisabled()) return;
|
||||
|
||||
post(
|
||||
`${root}/api/collect`,
|
||||
{
|
||||
type,
|
||||
payload,
|
||||
},
|
||||
res => (cache = res),
|
||||
);
|
||||
return fetch(endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ type, payload }),
|
||||
headers: assign({ 'Content-Type': 'application/json' }, { ['x-umami-cache']: cache }),
|
||||
})
|
||||
.then(res => res.text())
|
||||
.then(text => (cache = text));
|
||||
};
|
||||
|
||||
const trackView = (url = currentUrl, referrer = currentRef, uuid = website) => {
|
||||
const trackView = (url = currentUrl, referrer = currentRef, uuid = website) =>
|
||||
collect(
|
||||
'pageview',
|
||||
assign(getPayload(), {
|
||||
@ -95,9 +82,8 @@ import { removeTrailingSlash } from '../lib/url';
|
||||
referrer,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const trackEvent = (event_name = 'custom', event_data, url = currentUrl, uuid = website) => {
|
||||
const trackEvent = (event_name, event_data, url = currentUrl, uuid = website) =>
|
||||
collect(
|
||||
'event',
|
||||
assign(getPayload(), {
|
||||
@ -107,49 +93,45 @@ import { removeTrailingSlash } from '../lib/url';
|
||||
event_data,
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
/* Handle events */
|
||||
|
||||
const sendEvent = name => {
|
||||
const payload = getPayload();
|
||||
|
||||
payload.event_name = name;
|
||||
|
||||
const data = JSON.stringify({
|
||||
type: 'event',
|
||||
payload,
|
||||
});
|
||||
|
||||
fetch(`${root}/api/collect`, {
|
||||
method: 'POST',
|
||||
body: data,
|
||||
keepalive: true,
|
||||
});
|
||||
};
|
||||
|
||||
const addEvents = node => {
|
||||
const elements = node.querySelectorAll(eventSelect);
|
||||
Array.prototype.forEach.call(elements, addEvent);
|
||||
};
|
||||
|
||||
const addEvent = element => {
|
||||
(element.getAttribute('class') || '').split(' ').forEach(className => {
|
||||
const get = element.getAttribute.bind(element);
|
||||
(get('class') || '').split(' ').forEach(className => {
|
||||
if (!eventClass.test(className)) return;
|
||||
|
||||
const [, type, name] = className.split('--');
|
||||
const [, event, name] = className.split('--');
|
||||
|
||||
const listener = listeners[className]
|
||||
? listeners[className]
|
||||
: (listeners[className] = () => {
|
||||
if (element.tagName === 'A') {
|
||||
sendEvent(name);
|
||||
: (listeners[className] = e => {
|
||||
if (
|
||||
event === 'click' &&
|
||||
element.tagName === 'A' &&
|
||||
!(
|
||||
e.ctrlKey ||
|
||||
e.shiftKey ||
|
||||
e.metaKey ||
|
||||
(e.button && e.button === 1) ||
|
||||
get('target')
|
||||
)
|
||||
) {
|
||||
e.preventDefault();
|
||||
trackEvent(name).then(() => {
|
||||
location.href = get('href');
|
||||
});
|
||||
} else {
|
||||
trackEvent(name);
|
||||
}
|
||||
});
|
||||
|
||||
element.addEventListener(type, listener, true);
|
||||
element.addEventListener(event, listener, true);
|
||||
});
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user