Merge pull request #1332 from umami-software/dev

v1.36.0
This commit is contained in:
Mike Cao 2022-07-23 14:07:54 -07:00 committed by GitHub
commit bcabc25300
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
124 changed files with 3034 additions and 247 deletions

View File

@ -22,6 +22,7 @@ export default function MetricsTable({
filterOptions,
limit,
onDataLoad,
delay = null,
...props
}) {
const [{ startDate, endDate, modified }] = useDateRange(websiteId);
@ -46,9 +47,9 @@ export default function MetricsTable({
country,
},
onDataLoad,
delay: DEFAULT_ANIMATION_DURATION,
delay: delay || DEFAULT_ANIMATION_DURATION,
},
[modified, url, referrer, os, browser, device, country],
[type, modified, url, referrer, os, browser, device, country],
);
const filteredData = useMemo(() => {

View File

@ -0,0 +1,47 @@
import React, { useState } from 'react';
import { useIntl, defineMessages } from 'react-intl';
import MetricsTable from './MetricsTable';
import FilterButtons from 'components/common/FilterButtons';
export const UTM_SOURCE = 'utm_source';
export const UTM_MEDIUM = 'utm_medium';
export const UTM_CAMPAIGN = 'utm_campaign';
export const UTM_CONTENT = 'utm_content';
export const UTM_TERM = 'utm_term';
const messages = defineMessages({
utm_source: { id: 'metrics.utm_source', defaultMessage: 'UTM Source' },
utm_medium: { id: 'metrics.utm_medium', defaultMessage: 'UTM Medium' },
utm_campaign: { id: 'metrics.utm_campaign', defaultMessage: 'UTM Campaign' },
utm_content: { id: 'metrics.utm_content', defaultMessage: 'UTM Content' },
utm_term: { id: 'metrics.utm_term', defaultMessage: 'UTM Term' },
views: { id: 'metrics.views', defaultMessage: 'Views' },
none: { id: 'label.none', defaultMessage: 'None' },
});
export default function UTMTable({ websiteId, showFilters, ...props }) {
const [type, setType] = useState(UTM_SOURCE);
const { formatMessage } = useIntl();
const buttons = [
{ label: formatMessage(messages.utm_source), value: UTM_SOURCE },
{ label: formatMessage(messages.utm_medium), value: UTM_MEDIUM },
{ label: formatMessage(messages.utm_campaign), value: UTM_CAMPAIGN },
{ label: formatMessage(messages.utm_content), value: UTM_CONTENT },
{ label: formatMessage(messages.utm_term), value: UTM_TERM },
];
return (
<>
{showFilters && <FilterButtons buttons={buttons} selected={type} onClick={setType} />}
<MetricsTable
{...props}
title={formatMessage(messages[type])}
type={type}
metric={formatMessage(messages.views)}
websiteId={websiteId}
delay={0}
/>
</>
);
}

View File

@ -23,6 +23,7 @@ import usePageQuery from 'hooks/usePageQuery';
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
import styles from './WebsiteDetails.module.css';
import ScreenTable from 'components/metrics/ScreenTable';
import UTMTable from 'components/metrics/UTMTable';
const views = {
url: PagesTable,
@ -34,6 +35,7 @@ const views = {
country: CountriesTable,
language: LanguagesTable,
event: EventsTable,
utm: UTMTable,
};
export default function WebsiteDetails({ websiteId }) {
@ -94,6 +96,10 @@ export default function WebsiteDetails({ websiteId }) {
label: <FormattedMessage id="metrics.events" defaultMessage="Events" />,
value: resolve({ view: 'event' }),
},
{
label: <FormattedMessage id="metrics.utm" defaultMessage="UTM" />,
value: resolve({ view: 'utm' }),
},
];
const tableProps = {

View File

@ -106,6 +106,12 @@
"metrics.referrers": "التحويلات",
"metrics.screens": "Screens",
"metrics.unique-visitors": "زائرون فريدون",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "مشاهدات",
"metrics.visitors": "زوار"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referents",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Visitants únics",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Vistes",
"metrics.visitors": "Visitants"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Odkazy",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Jedinečné návštěvy",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Zobrazení",
"metrics.visitors": "Návštěvy"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Henvisninger",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unikke besøgende",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Visninger",
"metrics.visitors": "Besøgende"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referrer",
"metrics.screens": "Bildschirmauflösungen",
"metrics.unique-visitors": "Eindeutige Besucher",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Aufrufe",
"metrics.visitors": "Besucher"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Παραπομπές",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Μοναδικοί επισκέπτες",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Προβολές",
"metrics.visitors": "Επισκέπτες"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referrers",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unique visitors",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Views",
"metrics.visitors": "Visitors"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referrers",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unique visitors",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Views",
"metrics.visitors": "Visitors"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referentes",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Visitantes únicos",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Vistas",
"metrics.visitors": "Visitantes"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "ارجاع دهندگان",
"metrics.screens": "Screens",
"metrics.unique-visitors": "بازدیدکننده‌های یکتا",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "بازدید",
"metrics.visitors": "بازدیدکننده"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Viittaajat",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Yksittäiset kävijät",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Näyttökerrat",
"metrics.visitors": "Vierailijat"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Framsendingar",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Einsýna vitjanir",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Sýningar",
"metrics.visitors": "Vitjandi"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Sources",
"metrics.screens": "Tailles d'écran",
"metrics.unique-visitors": "Visiteurs uniques",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Vues",
"metrics.visitors": "Visiteurs"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Orixes",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Visitas únicas",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Visualizacións",
"metrics.visitors": "Visitantes"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "מפנים",
"metrics.screens": "Screens",
"metrics.unique-visitors": "מבקרים ייחודיים",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "צפיות",
"metrics.visitors": "מבקרים"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "सन्दर्भदाता",
"metrics.screens": "Screens",
"metrics.unique-visitors": "अद्वितीय आगंतुकों",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "दृश्य",
"metrics.visitors": "आगंतुकों"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Hivatkozók",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Egyedi látogatók",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Megtekintések",
"metrics.visitors": "Látogatók"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Perujuk",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Pengunjung unik",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Tampilan",
"metrics.visitors": "Pengunjung"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referrers",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Visitatori unici",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Visualizzazioni",
"metrics.visitors": "Visitatori"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "リファラー",
"metrics.screens": "Screens",
"metrics.unique-visitors": "ユニーク訪問者数",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "閲覧数",
"metrics.visitors": "訪問者数"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "리퍼러",
"metrics.screens": "Screens",
"metrics.unique-visitors": "순방문자(UV)",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "조회수",
"metrics.visitors": "방문객"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referrers",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unikalūs lankytojai",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Peržiūros",
"metrics.visitors": "Lankytojai"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Чиглүүлэгч",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Зочин",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Үзсэн",
"metrics.visitors": "Зочин"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Perujuk",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Pelawat unik",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Lawatan",
"metrics.visitors": "Pelawat"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referanser",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unike besøkende",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Visninger",
"metrics.visitors": "Besøkende"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Verwijzers",
"metrics.screens": "Schermen",
"metrics.unique-visitors": "Unieke bezoekers",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Weergaven",
"metrics.visitors": "Bezoekers"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Źródła odsyłające",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unikalni odwiedzający",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Wyświetlenia",
"metrics.visitors": "Odwiedzający"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referências",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Visitantes únicos",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Visualizações",
"metrics.visitors": "Visitantes"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Referenciadores",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Visitantes únicos",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Visualizações",
"metrics.visitors": "Visitantes"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Site-uri de proveniență",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Vizitatori unici",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Vizualizări",
"metrics.visitors": "Vizitatori"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Источники",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Уникальные посетители",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Просмотры",
"metrics.visitors": "Посетители"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Odkazy",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Jedinečné návštevy",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Zobrazení",
"metrics.visitors": "Návštevy"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Viri",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unikatni obiskovalci",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Ogledi",
"metrics.visitors": "Obiskovalci"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Hänvisare",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Unika besökare",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Visningar",
"metrics.visitors": "Besökare"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "குறிப்பிடுவோர்",
"metrics.screens": "Screens",
"metrics.unique-visitors": "தனிப்பட்ட பார்வையாளர்கள்",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "பார்வைகள்",
"metrics.visitors": "பார்வையாளர்கள்"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Yönlendirenler",
"metrics.screens": "Ekranlar",
"metrics.unique-visitors": "Tekil kullanıcı",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Görüntüleme",
"metrics.visitors": "Ziyaretçi"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Джерела",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Унікальні відвідувачі",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Перегляди",
"metrics.visitors": "Відвідувачі"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "بھیجنے والے",
"metrics.screens": "Screens",
"metrics.unique-visitors": "منفرد زائرین",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "مناظر",
"metrics.visitors": "زائرین"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "Liên kết giới thiệu",
"metrics.screens": "Screens",
"metrics.unique-visitors": "Khách truy cập một lần",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "Xem",
"metrics.visitors": "Khách"
}

View File

@ -37,7 +37,7 @@
"label.more": "更多",
"label.name": "名字",
"label.new-password": "新密码",
"label.none": "None",
"label.none": "",
"label.owner": "所有者",
"label.password": "密码",
"label.passwords-dont-match": "密码不一致",
@ -104,8 +104,14 @@
"metrics.page-views": "页面浏览量",
"metrics.pages": "网页",
"metrics.referrers": "来源域名",
"metrics.screens": "Screens",
"metrics.screens": "屏幕尺寸",
"metrics.unique-visitors": "独立访客",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "浏览量",
"metrics.visitors": "访客"
}

View File

@ -106,6 +106,12 @@
"metrics.referrers": "指入域名",
"metrics.screens": "Screens",
"metrics.unique-visitors": "獨立訪客",
"metrics.utm": "UTM",
"metrics.utm_campaign": "UTM Campaign",
"metrics.utm_content": "UTM Content",
"metrics.utm_medium": "UTM Medium",
"metrics.utm_source": "UTM Source",
"metrics.utm_term": "UTM Term",
"metrics.views": "頁面流量",
"metrics.visitors": "獨立訪客"
}

View File

@ -65,8 +65,10 @@ export const EVENT_COLORS = [
'#ffec16',
];
export const RELATIONAL = 'relational';
export const POSTGRESQL = 'postgresql';
export const MYSQL = 'mysql';
export const CLICKHOUSE = 'clickhouse';
export const MYSQL_DATE_FORMATS = {
minute: '%Y-%m-%d %H:%i:00',
@ -84,6 +86,16 @@ export const POSTGRESQL_DATE_FORMATS = {
year: 'YYYY-01-01',
};
export const CLICKHOUSE_DATE_FORMATS = {
minute: '%Y-%m-%d %H:%M:00',
hour: '%Y-%m-%d %H:00:00',
day: '%Y-%m-%d',
month: '%Y-%m-01',
year: '%Y-01-01',
};
export const FILTER_IGNORED = Symbol.for('filter-ignored');
export const DOMAIN_REGEX =
/^(localhost(:[1-9]\d{0,4})?|((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63})$/;

259
lib/db.js
View File

@ -1,5 +1,17 @@
import { PrismaClient } from '@prisma/client';
import { ClickHouse } from 'clickhouse';
import chalk from 'chalk';
import {
MYSQL,
MYSQL_DATE_FORMATS,
POSTGRESQL,
POSTGRESQL_DATE_FORMATS,
CLICKHOUSE,
RELATIONAL,
FILTER_IGNORED,
} from 'lib/constants';
import moment from 'moment-timezone';
import { CLICKHOUSE_DATE_FORMATS } from './constants';
BigInt.prototype.toJSON = function () {
return Number(this);
@ -18,7 +30,7 @@ function logQuery(e) {
console.log(chalk.yellow(e.params), '->', e.query, chalk.greenBright(`${e.duration}ms`));
}
function getClient(options) {
function getPrismaClient(options) {
const prisma = new PrismaClient(options);
if (process.env.LOG_QUERY) {
@ -28,10 +40,251 @@ function getClient(options) {
return prisma;
}
const prisma = global.prisma || getClient(options);
function getClickhouseClient() {
if (!process.env.ANALYTICS_URL) {
return null;
}
const url = new URL(process.env.ANALYTICS_URL);
const database = url.pathname.replace('/', '');
return new ClickHouse({
url: url.hostname,
port: Number(url.port),
basicAuth: url.password
? {
username: url.username || 'default',
password: url.password,
}
: null,
format: 'json',
config: {
database,
},
});
}
const prisma = global.prisma || getPrismaClient(options);
const clickhouse = global.clickhouse || getClickhouseClient();
if (process.env.NODE_ENV !== 'production') {
global.prisma = prisma;
global.clickhouse = clickhouse;
}
export default prisma;
export { prisma, clickhouse };
export function getDatabase() {
const type =
process.env.DATABASE_TYPE ||
(process.env.DATABASE_URL && process.env.DATABASE_URL.split(':')[0]);
if (type === 'postgres') {
return POSTGRESQL;
}
return type;
}
export function getAnalyticsDatabase() {
const type =
process.env.ANALYTICS_TYPE ||
(process.env.ANALYTICS_URL && process.env.ANALYTICS_URL.split(':')[0]);
if (type === 'postgres') {
return POSTGRESQL;
}
if (!type) {
return getDatabase();
}
return type;
}
export function getDateStringQueryClickhouse(data, unit) {
return `formatDateTime(${data}, '${CLICKHOUSE_DATE_FORMATS[unit]}')`;
}
export function getDateQuery(field, unit, timezone) {
const db = getDatabase();
if (db === POSTGRESQL) {
if (timezone) {
return `to_char(date_trunc('${unit}', ${field} at time zone '${timezone}'), '${POSTGRESQL_DATE_FORMATS[unit]}')`;
}
return `to_char(date_trunc('${unit}', ${field}), '${POSTGRESQL_DATE_FORMATS[unit]}')`;
}
if (db === MYSQL) {
if (timezone) {
const tz = moment.tz(timezone).format('Z');
return `date_format(convert_tz(${field},'+00:00','${tz}'), '${MYSQL_DATE_FORMATS[unit]}')`;
}
return `date_format(${field}, '${MYSQL_DATE_FORMATS[unit]}')`;
}
}
export function getDateQueryClickhouse(field, unit, timezone) {
if (timezone) {
return `date_trunc('${unit}', ${field},'${timezone}')`;
}
return `date_trunc('${unit}', ${field})`;
}
export function getDateFormatClickhouse(date) {
return `parseDateTimeBestEffort('${date.toUTCString()}')`;
}
export function getBetweenDatesClickhouse(field, start_at, end_at) {
return `${field} between ${getDateFormatClickhouse(start_at)}
and ${getDateFormatClickhouse(end_at)}`;
}
export function getTimestampInterval(field) {
const db = getDatabase();
if (db === POSTGRESQL) {
return `floor(extract(epoch from max(${field}) - min(${field})))`;
}
if (db === MYSQL) {
return `floor(unix_timestamp(max(${field})) - unix_timestamp(min(${field})))`;
}
}
export function getFilterQuery(table, column, filters = {}, params = []) {
const query = Object.keys(filters).reduce((arr, key) => {
const filter = filters[key];
if (filter === undefined || filter === FILTER_IGNORED) {
return arr;
}
switch (key) {
case 'url':
if (table === 'pageview' || table === 'event') {
arr.push(`and ${table}.${key}=$${params.length + 1}`);
params.push(decodeURIComponent(filter));
console.log(params);
}
break;
case 'os':
case 'browser':
case 'device':
case 'country':
if (table === 'session') {
arr.push(`and ${table}.${key}=$${params.length + 1}`);
params.push(decodeURIComponent(filter));
}
break;
case 'event_type':
if (table === 'event') {
arr.push(`and ${table}.${key}=$${params.length + 1}`);
params.push(decodeURIComponent(filter));
}
break;
case 'referrer':
if (table === 'pageview' || table === 'event') {
arr.push(`and ${table}.referrer like $${params.length + 1}`);
params.push(`%${decodeURIComponent(filter)}%`);
}
break;
case 'domain':
if (table === 'pageview') {
arr.push(`and ${table}.referrer not like $${params.length + 1}`);
arr.push(`and ${table}.referrer not like '/%'`);
params.push(`%://${filter}/%`);
}
break;
}
return arr;
}, []);
return query.join('\n');
}
export function parseFilters(table, column, filters = {}, params = [], sessionKey = 'session_id') {
const { domain, url, event_url, referrer, os, browser, device, country, event_type } = filters;
const pageviewFilters = { domain, url, referrer };
const sessionFilters = { os, browser, device, country };
const eventFilters = { url: event_url, event_type };
return {
pageviewFilters,
sessionFilters,
eventFilters,
event: { event_type },
joinSession:
os || browser || device || country
? `inner join session on ${table}.${sessionKey} = session.${sessionKey}`
: '',
pageviewQuery: getFilterQuery('pageview', column, pageviewFilters, params),
sessionQuery: getFilterQuery('session', column, sessionFilters, params),
eventQuery: getFilterQuery('event', column, eventFilters, params),
};
}
export function replaceQueryClickhouse(string, params = []) {
let formattedString = string;
params.forEach((a, i) => {
let replace = a;
if (typeof a === 'string' || a instanceof String) {
replace = `'${replace}'`;
}
formattedString = formattedString.replace(`$${i + 1}`, replace);
});
return formattedString;
}
export async function runQuery(query) {
return query.catch(e => {
throw e;
});
}
export async function rawQuery(query, params = []) {
const db = getDatabase();
if (db !== POSTGRESQL && db !== MYSQL) {
return Promise.reject(new Error('Unknown database.'));
}
const sql = db === MYSQL ? query.replace(/\$[0-9]+/g, '?') : query;
return runQuery(prisma.$queryRawUnsafe.apply(prisma, [sql, ...params]));
}
export async function rawQueryClickhouse(query, params = [], debug = false) {
let formattedQuery = replaceQueryClickhouse(query, params);
if (debug || process.env.LOG_QUERY) {
console.log(formattedQuery);
}
return clickhouse.query(formattedQuery).toPromise();
}
export async function runAnalyticsQuery(queries) {
const db = getAnalyticsDatabase();
if (db === POSTGRESQL || db === MYSQL) {
return queries[`${RELATIONAL}`]();
}
if (db === CLICKHOUSE) {
return queries[`${CLICKHOUSE}`]();
}
}

View File

@ -1,144 +0,0 @@
import { MYSQL, MYSQL_DATE_FORMATS, POSTGRESQL, POSTGRESQL_DATE_FORMATS } from 'lib/constants';
import prisma from 'lib/db';
import moment from 'moment-timezone';
export function getDatabase() {
const type =
process.env.DATABASE_TYPE ||
(process.env.DATABASE_URL && process.env.DATABASE_URL.split(':')[0]);
if (type === 'postgres') {
return 'postgresql';
}
return type;
}
export function getDateQuery(field, unit, timezone) {
const db = getDatabase();
if (db === POSTGRESQL) {
if (timezone) {
return `to_char(date_trunc('${unit}', ${field} at time zone '${timezone}'), '${POSTGRESQL_DATE_FORMATS[unit]}')`;
}
return `date_trunc('${unit}', ${field})`;
}
if (db === MYSQL) {
if (timezone) {
const tz = moment.tz(timezone).format('Z');
return `date_format(convert_tz(${field},'+00:00','${tz}'), '${MYSQL_DATE_FORMATS[unit]}')`;
}
return `${field}`;
}
}
export function getTimestampInterval(field) {
const db = getDatabase();
if (db === POSTGRESQL) {
return `floor(extract(epoch from max(${field}) - min(${field})))`;
}
if (db === MYSQL) {
return `floor(unix_timestamp(max(${field})) - unix_timestamp(min(${field})))`;
}
}
export function getFilterQuery(table, column, filters = {}, params = []) {
const query = Object.keys(filters).reduce((arr, key) => {
const value = filters[key];
if (!value || value === true) {
return arr;
}
switch (key) {
case 'url':
if (table === 'pageview' || table === 'event') {
arr.push(`and ${table}.${key}=$${params.length + 1}`);
params.push(decodeURIComponent(value));
}
break;
case 'os':
case 'browser':
case 'device':
case 'country':
if (table === 'session') {
arr.push(`and ${table}.${key}=$${params.length + 1}`);
params.push(decodeURIComponent(value));
}
break;
case 'event_type':
if (table === 'event') {
arr.push(`and ${table}.${key}=$${params.length + 1}`);
params.push(decodeURIComponent(value));
}
break;
case 'referrer':
if (table === 'pageview') {
arr.push(`and ${table}.referrer like $${params.length + 1} `);
arr.push(`and ${table}.referrer not like '/%'`);
params.push(`%${decodeURIComponent(value)}%`);
}
break;
case 'domain':
if (table === 'pageview') {
arr.push(`and ${table}.referrer not like $${params.length + 1}`);
arr.push(`and ${table}.referrer not like '/%'`);
params.push(`%://${value}/%`);
}
break;
}
return arr;
}, []);
return query.join('\n');
}
export function parseFilters(table, column, filters = {}, params = []) {
const { domain, url, event_url, referrer, os, browser, device, country, event_type } = filters;
const pageviewFilters = { domain, url, referrer };
const sessionFilters = { os, browser, device, country };
const eventFilters = { url: event_url, event_type };
return {
pageviewFilters,
sessionFilters,
eventFilters,
event: { event_type },
joinSession:
os || browser || device || country
? `inner join session on ${table}.session_id = session.session_id`
: '',
pageviewQuery: getFilterQuery('pageview', column, pageviewFilters, params),
sessionQuery: getFilterQuery('session', column, sessionFilters, params),
eventQuery: getFilterQuery('event', column, eventFilters, params),
};
}
export async function runQuery(query) {
return query.catch(e => {
throw e;
});
}
export async function rawQuery(query, params = []) {
const db = getDatabase();
if (db !== POSTGRESQL && db !== MYSQL) {
return Promise.reject(new Error('Unknown database.'));
}
const sql = db === MYSQL ? query.replace(/\$[0-9]+/g, '?') : query;
return runQuery(prisma.$queryRawUnsafe.apply(prisma, [sql, ...params]));
}

View File

@ -37,6 +37,8 @@ export async function getSession(req) {
let session = await getSessionByUuid(session_uuid);
session = Array.isArray(session) && session[0] ? session[0] : null;
if (!session) {
try {
session = await createSession(website_id, {
@ -65,5 +67,6 @@ export async function getSession(req) {
return {
website_id,
session_id,
session_uuid,
};
}

View File

@ -1,6 +1,6 @@
{
"name": "umami",
"version": "1.35.0",
"version": "1.36.0",
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
"author": "Mike Cao <mike@mikecao.com>",
"license": "MIT",
@ -60,6 +60,7 @@
"chalk": "^4.1.1",
"chart.js": "^2.9.4",
"classnames": "^2.3.1",
"clickhouse": "^2.5.0",
"colord": "^2.9.2",
"cors": "^2.8.5",
"cross-spawn": "^7.0.3",

View File

@ -60,7 +60,7 @@ export default async (req, res) => {
await useSession(req, res);
const {
session: { website_id, session_id },
session: { website_id, session_id, session_uuid },
} = req;
const { type, payload } = getJsonBody(req);
@ -72,9 +72,9 @@ export default async (req, res) => {
}
if (type === 'pageview') {
await savePageView(website_id, session_id, url, referrer);
await savePageView(website_id, { session_id, session_uuid, url, referrer });
} else if (type === 'event') {
await saveEvent(website_id, session_id, url, event_type, event_value);
await saveEvent(website_id, { session_id, session_uuid, url, event_type, event_value });
} else {
return badRequest(res);
}

View File

@ -1,10 +1,12 @@
import { getPageviewMetrics, getSessionMetrics, getWebsiteById } from 'queries';
import { getPageviewMetrics, getSessionMetrics, getWebsiteById, getPageviewParams } from 'queries';
import { ok, methodNotAllowed, unauthorized, badRequest } from 'lib/response';
import { allowQuery } from 'lib/auth';
import { useCors } from 'lib/middleware';
import { FILTER_IGNORED } from 'lib/constants';
const sessionColumns = ['browser', 'os', 'device', 'screen', 'country', 'language'];
const pageviewColumns = ['url', 'referrer'];
const paramTypes = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'ref'];
function getTable(type) {
if (type === 'event') {
@ -39,6 +41,52 @@ export default async (req, res) => {
const startDate = new Date(+start_at);
const endDate = new Date(+end_at);
if (paramTypes.includes(type)) {
const column = 'url';
const table = getTable(type);
let domain;
if (type === 'referrer') {
const website = await getWebsiteById(websiteId);
if (!website) {
return badRequest(res);
}
domain = website.domain;
}
const filters = {
domain,
url: type !== 'url' && table !== 'event' ? url : undefined,
referrer: type !== 'referrer' ? referrer : true,
os: type !== 'os' ? os : undefined,
browser: type !== 'browser' ? browser : undefined,
device: type !== 'device' ? device : undefined,
country: type !== 'country' ? country : undefined,
event_url: type !== 'url' && table === 'event' ? url : undefined,
};
let data = await getPageviewParams(
type,
websiteId,
startDate,
endDate,
column,
table,
filters,
);
let terms = {};
new Set(data.map(i => i.param)).forEach(term => (terms[term] = null));
for (let { param } of data) terms[param] += 1;
return ok(
res,
Object.keys(terms).map(i => ({ x: i, y: terms[i] })),
);
}
if (sessionColumns.includes(type)) {
let data = await getSessionMetrics(websiteId, startDate, endDate, type, {
os,
@ -83,7 +131,7 @@ export default async (req, res) => {
const filters = {
domain,
url: type !== 'url' && table !== 'event' ? url : undefined,
referrer: type !== 'referrer' ? referrer : true,
referrer: type !== 'referrer' && table !== 'event' ? referrer : FILTER_IGNORED,
os: type !== 'os' ? os : undefined,
browser: type !== 'browser' ? browser : undefined,
device: type !== 'device' ? device : undefined,

View File

@ -34,7 +34,7 @@ export default async (req, res) => {
device,
country,
}),
getPageviewStats(websiteId, startDate, endDate, tz, unit, 'distinct pageview.session_id', {
getPageviewStats(websiteId, startDate, endDate, tz, unit, 'distinct pageview.', {
url,
os,
browser,

View File

@ -785,6 +785,42 @@
"value": "زائرون فريدون"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Visitants únics"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Jedinečné návštěvy"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Unikke besøgende"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Eindeutige Besucher"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Μοναδικοί επισκέπτες"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Unique visitors"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Unique visitors"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Visitantes únicos"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -769,6 +769,42 @@
"value": "بازدیدکننده‌های یکتا"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Yksittäiset kävijät"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Einsýna vitjanir"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -781,6 +781,42 @@
"value": "Visiteurs uniques"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Visitas únicas"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -765,6 +765,42 @@
"value": "מבקרים ייחודיים"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -773,6 +773,42 @@
"value": "अद्वितीय आगंतुकों"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Egyedi látogatók"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -753,6 +753,42 @@
"value": "Pengunjung unik"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -789,6 +789,42 @@
"value": "Visitatori unici"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -757,6 +757,42 @@
"value": "ユニーク訪問者数"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -757,6 +757,42 @@
"value": "순방문자(UV)"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -910,6 +910,42 @@
"value": "Unikalūs lankytojai"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Зочин"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -777,6 +777,42 @@
"value": "Pelawat unik"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -789,6 +789,42 @@
"value": "Unike besøkende"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Unieke bezoekers"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Unikalni odwiedzający"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -789,6 +789,42 @@
"value": "Visitantes únicos"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -789,6 +789,42 @@
"value": "Visitantes únicos"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Vizitatori unici"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -757,6 +757,42 @@
"value": "Уникальные посетители"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Jedinečné návštevy"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "Unikatni obiskovalci"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -789,6 +789,42 @@
"value": "Unika besökare"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -777,6 +777,42 @@
"value": "தனிப்பட்ட பார்வையாளர்கள்"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -749,6 +749,42 @@
"value": "Tekil kullanıcı"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -761,6 +761,42 @@
"value": "Унікальні відвідувачі"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -785,6 +785,42 @@
"value": "منفرد زائرین"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -769,6 +769,42 @@
"value": "Khách truy cập một lần"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -250,7 +250,7 @@
"label.none": [
{
"type": 0,
"value": "None"
"value": ""
}
],
"label.owner": [
@ -764,7 +764,7 @@
"metrics.screens": [
{
"type": 0,
"value": "Screens"
"value": "屏幕尺寸"
}
],
"metrics.unique-visitors": [
@ -773,6 +773,42 @@
"value": "独立访客"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -769,6 +769,42 @@
"value": "獨立訪客"
}
],
"metrics.utm": [
{
"type": 0,
"value": "UTM"
}
],
"metrics.utm_campaign": [
{
"type": 0,
"value": "UTM Campaign"
}
],
"metrics.utm_content": [
{
"type": 0,
"value": "UTM Content"
}
],
"metrics.utm_medium": [
{
"type": 0,
"value": "UTM Medium"
}
],
"metrics.utm_source": [
{
"type": 0,
"value": "UTM Source"
}
],
"metrics.utm_term": [
{
"type": 0,
"value": "UTM Term"
}
],
"metrics.views": [
{
"type": 0,

View File

@ -1,5 +1,4 @@
import { runQuery } from 'lib/queries';
import prisma from 'lib/db';
import { prisma, runQuery } from 'lib/db';
export async function createAccount(data) {
return runQuery(

View File

@ -1,5 +1,4 @@
import { runQuery } from 'lib/queries';
import prisma from 'lib/db';
import { prisma, runQuery } from 'lib/db';
export async function deleteAccount(user_id) {
return runQuery(

View File

@ -1,5 +1,4 @@
import { runQuery } from 'lib/queries';
import prisma from 'lib/db';
import { prisma, runQuery } from 'lib/db';
export async function getAccountById(user_id) {
return runQuery(

View File

@ -1,5 +1,4 @@
import { runQuery } from 'lib/queries';
import prisma from 'lib/db';
import { prisma, runQuery } from 'lib/db';
export async function getAccountByUsername(username) {
return runQuery(

View File

@ -1,5 +1,4 @@
import { runQuery } from 'lib/queries';
import prisma from 'lib/db';
import { prisma, runQuery } from 'lib/db';
export async function getAccounts() {
return runQuery(

View File

@ -1,5 +1,4 @@
import { runQuery } from 'lib/queries';
import prisma from 'lib/db';
import { prisma, runQuery } from 'lib/db';
export async function updateAccount(user_id, data) {
return runQuery(

View File

@ -1,5 +1,4 @@
import { runQuery } from 'lib/queries';
import prisma from 'lib/db';
import { prisma, runQuery } from 'lib/db';
export async function createWebsite(user_id, data) {
return runQuery(

Some files were not shown because too many files have changed in this diff Show More