diff --git a/components/metrics/MetricsTable.js b/components/metrics/MetricsTable.js
index 29121487..df4beb08 100644
--- a/components/metrics/MetricsTable.js
+++ b/components/metrics/MetricsTable.js
@@ -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(() => {
diff --git a/components/metrics/UTMTable.js b/components/metrics/UTMTable.js
new file mode 100644
index 00000000..ba16f2f6
--- /dev/null
+++ b/components/metrics/UTMTable.js
@@ -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 && }
+
+ >
+ );
+}
diff --git a/components/pages/WebsiteDetails.js b/components/pages/WebsiteDetails.js
index 1b22d9ed..869b7a85 100644
--- a/components/pages/WebsiteDetails.js
+++ b/components/pages/WebsiteDetails.js
@@ -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: ,
value: resolve({ view: 'event' }),
},
+ {
+ label: ,
+ value: resolve({ view: 'utm' }),
+ },
];
const tableProps = {
diff --git a/lang/ar-SA.json b/lang/ar-SA.json
index 2a1a08aa..137c726f 100644
--- a/lang/ar-SA.json
+++ b/lang/ar-SA.json
@@ -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": "زوار"
}
diff --git a/lang/ca-ES.json b/lang/ca-ES.json
index 4bbc38d7..f822f9f7 100644
--- a/lang/ca-ES.json
+++ b/lang/ca-ES.json
@@ -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"
}
diff --git a/lang/cs-CZ.json b/lang/cs-CZ.json
index 30501f97..165f2512 100644
--- a/lang/cs-CZ.json
+++ b/lang/cs-CZ.json
@@ -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"
}
diff --git a/lang/da-DK.json b/lang/da-DK.json
index 48fde249..3621f63b 100644
--- a/lang/da-DK.json
+++ b/lang/da-DK.json
@@ -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"
}
diff --git a/lang/de-DE.json b/lang/de-DE.json
index c7fca4a1..86c750ed 100644
--- a/lang/de-DE.json
+++ b/lang/de-DE.json
@@ -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"
}
diff --git a/lang/el-GR.json b/lang/el-GR.json
index 6cf4b2ac..e82f9330 100644
--- a/lang/el-GR.json
+++ b/lang/el-GR.json
@@ -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": "Επισκέπτες"
}
diff --git a/lang/en-GB.json b/lang/en-GB.json
index 1580b500..7819d5fb 100644
--- a/lang/en-GB.json
+++ b/lang/en-GB.json
@@ -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"
}
diff --git a/lang/en-US.json b/lang/en-US.json
index 1580b500..7819d5fb 100644
--- a/lang/en-US.json
+++ b/lang/en-US.json
@@ -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"
}
diff --git a/lang/es-MX.json b/lang/es-MX.json
index 6615e308..115efc2c 100644
--- a/lang/es-MX.json
+++ b/lang/es-MX.json
@@ -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"
}
diff --git a/lang/fa-IR.json b/lang/fa-IR.json
index a79b145a..af456c9a 100644
--- a/lang/fa-IR.json
+++ b/lang/fa-IR.json
@@ -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": "بازدیدکننده"
}
diff --git a/lang/fi-FI.json b/lang/fi-FI.json
index 5a30072b..e56ead62 100644
--- a/lang/fi-FI.json
+++ b/lang/fi-FI.json
@@ -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"
}
diff --git a/lang/fo-FO.json b/lang/fo-FO.json
index 0187dcbb..3d52dd2e 100644
--- a/lang/fo-FO.json
+++ b/lang/fo-FO.json
@@ -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"
}
diff --git a/lang/fr-FR.json b/lang/fr-FR.json
index 04c2f4e8..2c3d4802 100644
--- a/lang/fr-FR.json
+++ b/lang/fr-FR.json
@@ -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"
}
diff --git a/lang/ga-ES.json b/lang/ga-ES.json
index 0a13935d..4c5a45c1 100644
--- a/lang/ga-ES.json
+++ b/lang/ga-ES.json
@@ -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"
}
diff --git a/lang/he-IL.json b/lang/he-IL.json
index 8edb685d..f333e3e9 100644
--- a/lang/he-IL.json
+++ b/lang/he-IL.json
@@ -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": "מבקרים"
}
diff --git a/lang/hi-IN.json b/lang/hi-IN.json
index f139dbdd..fe57c6b3 100644
--- a/lang/hi-IN.json
+++ b/lang/hi-IN.json
@@ -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": "आगंतुकों"
}
diff --git a/lang/hu-HU.json b/lang/hu-HU.json
index 261d736e..5057a2dc 100644
--- a/lang/hu-HU.json
+++ b/lang/hu-HU.json
@@ -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"
}
diff --git a/lang/id-ID.json b/lang/id-ID.json
index 225c4070..460f83f2 100644
--- a/lang/id-ID.json
+++ b/lang/id-ID.json
@@ -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"
}
diff --git a/lang/it-IT.json b/lang/it-IT.json
index 88dfd30a..c3acc7ee 100644
--- a/lang/it-IT.json
+++ b/lang/it-IT.json
@@ -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"
}
diff --git a/lang/ja-JP.json b/lang/ja-JP.json
index 1055319f..cdf8f9c2 100644
--- a/lang/ja-JP.json
+++ b/lang/ja-JP.json
@@ -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": "訪問者数"
}
diff --git a/lang/ko-KR.json b/lang/ko-KR.json
index fa22decf..6ec9556d 100644
--- a/lang/ko-KR.json
+++ b/lang/ko-KR.json
@@ -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": "방문객"
}
diff --git a/lang/lt-LT.json b/lang/lt-LT.json
index e6a8e9ff..53c1d371 100644
--- a/lang/lt-LT.json
+++ b/lang/lt-LT.json
@@ -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"
}
diff --git a/lang/mn-MN.json b/lang/mn-MN.json
index 488a0eec..dccd18fc 100644
--- a/lang/mn-MN.json
+++ b/lang/mn-MN.json
@@ -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": "Зочин"
}
diff --git a/lang/ms-MY.json b/lang/ms-MY.json
index be420352..c61085e5 100644
--- a/lang/ms-MY.json
+++ b/lang/ms-MY.json
@@ -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"
}
diff --git a/lang/nb-NO.json b/lang/nb-NO.json
index c42fbbbd..a997a897 100644
--- a/lang/nb-NO.json
+++ b/lang/nb-NO.json
@@ -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"
}
diff --git a/lang/nl-NL.json b/lang/nl-NL.json
index 888d62f2..4f332c72 100644
--- a/lang/nl-NL.json
+++ b/lang/nl-NL.json
@@ -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"
}
diff --git a/lang/pl-PL.json b/lang/pl-PL.json
index 8669f7ab..c4eab89e 100644
--- a/lang/pl-PL.json
+++ b/lang/pl-PL.json
@@ -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"
}
diff --git a/lang/pt-BR.json b/lang/pt-BR.json
index 7f56236f..d545adeb 100644
--- a/lang/pt-BR.json
+++ b/lang/pt-BR.json
@@ -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"
}
diff --git a/lang/pt-PT.json b/lang/pt-PT.json
index 018239fa..ec197e11 100644
--- a/lang/pt-PT.json
+++ b/lang/pt-PT.json
@@ -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"
}
diff --git a/lang/ro-RO.json b/lang/ro-RO.json
index 1be18a75..6d8bc2d0 100644
--- a/lang/ro-RO.json
+++ b/lang/ro-RO.json
@@ -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"
}
diff --git a/lang/ru-RU.json b/lang/ru-RU.json
index 43817f25..4d04c41b 100644
--- a/lang/ru-RU.json
+++ b/lang/ru-RU.json
@@ -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": "Посетители"
}
diff --git a/lang/sk-SK.json b/lang/sk-SK.json
index 0c810f61..7bc56b3c 100644
--- a/lang/sk-SK.json
+++ b/lang/sk-SK.json
@@ -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"
}
diff --git a/lang/sl-SI.json b/lang/sl-SI.json
index e0e77118..2c94a9fb 100644
--- a/lang/sl-SI.json
+++ b/lang/sl-SI.json
@@ -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"
}
diff --git a/lang/sv-SE.json b/lang/sv-SE.json
index 1ad63afb..2a0e4123 100644
--- a/lang/sv-SE.json
+++ b/lang/sv-SE.json
@@ -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"
}
diff --git a/lang/ta-IN.json b/lang/ta-IN.json
index 483373a2..bebe7811 100644
--- a/lang/ta-IN.json
+++ b/lang/ta-IN.json
@@ -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": "பார்வையாளர்கள்"
}
diff --git a/lang/tr-TR.json b/lang/tr-TR.json
index 81fdf3f9..78098149 100644
--- a/lang/tr-TR.json
+++ b/lang/tr-TR.json
@@ -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"
}
diff --git a/lang/uk-UA.json b/lang/uk-UA.json
index a6f6be84..20fe4112 100644
--- a/lang/uk-UA.json
+++ b/lang/uk-UA.json
@@ -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": "Відвідувачі"
}
diff --git a/lang/ur-PK.json b/lang/ur-PK.json
index 7b96268e..ff374da2 100644
--- a/lang/ur-PK.json
+++ b/lang/ur-PK.json
@@ -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": "زائرین"
}
diff --git a/lang/vi-VN.json b/lang/vi-VN.json
index efd00a09..5e5fac33 100644
--- a/lang/vi-VN.json
+++ b/lang/vi-VN.json
@@ -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"
}
diff --git a/lang/zh-CN.json b/lang/zh-CN.json
index 8e6a3bfc..fd37f49a 100644
--- a/lang/zh-CN.json
+++ b/lang/zh-CN.json
@@ -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": "访客"
}
diff --git a/lang/zh-TW.json b/lang/zh-TW.json
index 77ce6204..2071751b 100644
--- a/lang/zh-TW.json
+++ b/lang/zh-TW.json
@@ -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": "獨立訪客"
}
diff --git a/lib/constants.js b/lib/constants.js
index 2b332b21..f971ee02 100644
--- a/lib/constants.js
+++ b/lib/constants.js
@@ -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})$/;
diff --git a/lib/db.js b/lib/db.js
index b44b4d3e..378ca742 100644
--- a/lib/db.js
+++ b/lib/db.js
@@ -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}`]();
+ }
+}
diff --git a/lib/queries.js b/lib/queries.js
deleted file mode 100644
index b296d308..00000000
--- a/lib/queries.js
+++ /dev/null
@@ -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]));
-}
diff --git a/lib/session.js b/lib/session.js
index 15a349fd..4e0513b1 100644
--- a/lib/session.js
+++ b/lib/session.js
@@ -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,
};
}
diff --git a/package.json b/package.json
index 7c25ca35..d37ba99b 100644
--- a/package.json
+++ b/package.json
@@ -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 ",
"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",
diff --git a/pages/api/collect.js b/pages/api/collect.js
index acd031a9..4ff533b9 100644
--- a/pages/api/collect.js
+++ b/pages/api/collect.js
@@ -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);
}
diff --git a/pages/api/website/[id]/metrics.js b/pages/api/website/[id]/metrics.js
index 09229408..b12566fd 100644
--- a/pages/api/website/[id]/metrics.js
+++ b/pages/api/website/[id]/metrics.js
@@ -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,
diff --git a/pages/api/website/[id]/pageviews.js b/pages/api/website/[id]/pageviews.js
index 78145e8b..3bd572d9 100644
--- a/pages/api/website/[id]/pageviews.js
+++ b/pages/api/website/[id]/pageviews.js
@@ -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,
diff --git a/public/intl/messages/ar-SA.json b/public/intl/messages/ar-SA.json
index 5fd596e1..089dacc0 100644
--- a/public/intl/messages/ar-SA.json
+++ b/public/intl/messages/ar-SA.json
@@ -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,
diff --git a/public/intl/messages/ca-ES.json b/public/intl/messages/ca-ES.json
index 6a0a85d4..37bc240c 100644
--- a/public/intl/messages/ca-ES.json
+++ b/public/intl/messages/ca-ES.json
@@ -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,
diff --git a/public/intl/messages/cs-CZ.json b/public/intl/messages/cs-CZ.json
index 967261ab..c97984a2 100644
--- a/public/intl/messages/cs-CZ.json
+++ b/public/intl/messages/cs-CZ.json
@@ -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,
diff --git a/public/intl/messages/da-DK.json b/public/intl/messages/da-DK.json
index 9a478456..cc15e71c 100644
--- a/public/intl/messages/da-DK.json
+++ b/public/intl/messages/da-DK.json
@@ -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,
diff --git a/public/intl/messages/de-DE.json b/public/intl/messages/de-DE.json
index a332fd5f..79113df8 100644
--- a/public/intl/messages/de-DE.json
+++ b/public/intl/messages/de-DE.json
@@ -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,
diff --git a/public/intl/messages/el-GR.json b/public/intl/messages/el-GR.json
index 77ded169..52a4554e 100644
--- a/public/intl/messages/el-GR.json
+++ b/public/intl/messages/el-GR.json
@@ -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,
diff --git a/public/intl/messages/en-GB.json b/public/intl/messages/en-GB.json
index 9e07ff82..f3617455 100644
--- a/public/intl/messages/en-GB.json
+++ b/public/intl/messages/en-GB.json
@@ -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,
diff --git a/public/intl/messages/en-US.json b/public/intl/messages/en-US.json
index 9e07ff82..f3617455 100644
--- a/public/intl/messages/en-US.json
+++ b/public/intl/messages/en-US.json
@@ -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,
diff --git a/public/intl/messages/es-MX.json b/public/intl/messages/es-MX.json
index c2d82805..2a90fb86 100644
--- a/public/intl/messages/es-MX.json
+++ b/public/intl/messages/es-MX.json
@@ -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,
diff --git a/public/intl/messages/fa-IR.json b/public/intl/messages/fa-IR.json
index ed470e75..06f71286 100644
--- a/public/intl/messages/fa-IR.json
+++ b/public/intl/messages/fa-IR.json
@@ -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,
diff --git a/public/intl/messages/fi-FI.json b/public/intl/messages/fi-FI.json
index a2010b5a..1c274608 100644
--- a/public/intl/messages/fi-FI.json
+++ b/public/intl/messages/fi-FI.json
@@ -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,
diff --git a/public/intl/messages/fo-FO.json b/public/intl/messages/fo-FO.json
index 43da4b36..47baddf8 100644
--- a/public/intl/messages/fo-FO.json
+++ b/public/intl/messages/fo-FO.json
@@ -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,
diff --git a/public/intl/messages/fr-FR.json b/public/intl/messages/fr-FR.json
index 7368fddf..db07da60 100644
--- a/public/intl/messages/fr-FR.json
+++ b/public/intl/messages/fr-FR.json
@@ -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,
diff --git a/public/intl/messages/ga-ES.json b/public/intl/messages/ga-ES.json
index 67bfff79..a65f5c6c 100644
--- a/public/intl/messages/ga-ES.json
+++ b/public/intl/messages/ga-ES.json
@@ -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,
diff --git a/public/intl/messages/he-IL.json b/public/intl/messages/he-IL.json
index 315bc718..ff39fe5f 100644
--- a/public/intl/messages/he-IL.json
+++ b/public/intl/messages/he-IL.json
@@ -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,
diff --git a/public/intl/messages/hi-IN.json b/public/intl/messages/hi-IN.json
index f7475741..763c492a 100644
--- a/public/intl/messages/hi-IN.json
+++ b/public/intl/messages/hi-IN.json
@@ -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,
diff --git a/public/intl/messages/hu-HU.json b/public/intl/messages/hu-HU.json
index d66b060a..d659f447 100644
--- a/public/intl/messages/hu-HU.json
+++ b/public/intl/messages/hu-HU.json
@@ -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,
diff --git a/public/intl/messages/id-ID.json b/public/intl/messages/id-ID.json
index e6508c7b..69ad8e39 100644
--- a/public/intl/messages/id-ID.json
+++ b/public/intl/messages/id-ID.json
@@ -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,
diff --git a/public/intl/messages/it-IT.json b/public/intl/messages/it-IT.json
index 908b4953..ae2b2ec6 100644
--- a/public/intl/messages/it-IT.json
+++ b/public/intl/messages/it-IT.json
@@ -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,
diff --git a/public/intl/messages/ja-JP.json b/public/intl/messages/ja-JP.json
index f44adea4..b864fdf8 100644
--- a/public/intl/messages/ja-JP.json
+++ b/public/intl/messages/ja-JP.json
@@ -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,
diff --git a/public/intl/messages/ko-KR.json b/public/intl/messages/ko-KR.json
index 7702d1b8..43bb7de9 100644
--- a/public/intl/messages/ko-KR.json
+++ b/public/intl/messages/ko-KR.json
@@ -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,
diff --git a/public/intl/messages/lt-LT.json b/public/intl/messages/lt-LT.json
index 74ca9861..1946947d 100644
--- a/public/intl/messages/lt-LT.json
+++ b/public/intl/messages/lt-LT.json
@@ -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,
diff --git a/public/intl/messages/mn-MN.json b/public/intl/messages/mn-MN.json
index 0f8a7a68..3e39f2bc 100644
--- a/public/intl/messages/mn-MN.json
+++ b/public/intl/messages/mn-MN.json
@@ -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,
diff --git a/public/intl/messages/ms-MY.json b/public/intl/messages/ms-MY.json
index c0c758ef..39ca49e3 100644
--- a/public/intl/messages/ms-MY.json
+++ b/public/intl/messages/ms-MY.json
@@ -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,
diff --git a/public/intl/messages/nb-NO.json b/public/intl/messages/nb-NO.json
index 6477160f..b0209416 100644
--- a/public/intl/messages/nb-NO.json
+++ b/public/intl/messages/nb-NO.json
@@ -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,
diff --git a/public/intl/messages/nl-NL.json b/public/intl/messages/nl-NL.json
index 2151139d..ea391a0e 100644
--- a/public/intl/messages/nl-NL.json
+++ b/public/intl/messages/nl-NL.json
@@ -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,
diff --git a/public/intl/messages/pl-PL.json b/public/intl/messages/pl-PL.json
index 17273722..8d0e72db 100644
--- a/public/intl/messages/pl-PL.json
+++ b/public/intl/messages/pl-PL.json
@@ -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,
diff --git a/public/intl/messages/pt-BR.json b/public/intl/messages/pt-BR.json
index 6e3c5276..b9d058a7 100644
--- a/public/intl/messages/pt-BR.json
+++ b/public/intl/messages/pt-BR.json
@@ -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,
diff --git a/public/intl/messages/pt-PT.json b/public/intl/messages/pt-PT.json
index 7c4aa48c..919a96d5 100644
--- a/public/intl/messages/pt-PT.json
+++ b/public/intl/messages/pt-PT.json
@@ -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,
diff --git a/public/intl/messages/ro-RO.json b/public/intl/messages/ro-RO.json
index ff9b4914..2d74e5e2 100644
--- a/public/intl/messages/ro-RO.json
+++ b/public/intl/messages/ro-RO.json
@@ -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,
diff --git a/public/intl/messages/ru-RU.json b/public/intl/messages/ru-RU.json
index a9aa6300..52400370 100644
--- a/public/intl/messages/ru-RU.json
+++ b/public/intl/messages/ru-RU.json
@@ -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,
diff --git a/public/intl/messages/sk-SK.json b/public/intl/messages/sk-SK.json
index 99fde365..a7e36657 100644
--- a/public/intl/messages/sk-SK.json
+++ b/public/intl/messages/sk-SK.json
@@ -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,
diff --git a/public/intl/messages/sl-SI.json b/public/intl/messages/sl-SI.json
index 4f0f1fdf..b7d478ed 100644
--- a/public/intl/messages/sl-SI.json
+++ b/public/intl/messages/sl-SI.json
@@ -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,
diff --git a/public/intl/messages/sv-SE.json b/public/intl/messages/sv-SE.json
index 9a78d24a..21df2569 100644
--- a/public/intl/messages/sv-SE.json
+++ b/public/intl/messages/sv-SE.json
@@ -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,
diff --git a/public/intl/messages/ta-IN.json b/public/intl/messages/ta-IN.json
index df22a56c..d5a8e5d8 100644
--- a/public/intl/messages/ta-IN.json
+++ b/public/intl/messages/ta-IN.json
@@ -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,
diff --git a/public/intl/messages/tr-TR.json b/public/intl/messages/tr-TR.json
index ab02cf6a..8225c225 100644
--- a/public/intl/messages/tr-TR.json
+++ b/public/intl/messages/tr-TR.json
@@ -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,
diff --git a/public/intl/messages/uk-UA.json b/public/intl/messages/uk-UA.json
index 9e7daccf..b513fb68 100644
--- a/public/intl/messages/uk-UA.json
+++ b/public/intl/messages/uk-UA.json
@@ -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,
diff --git a/public/intl/messages/ur-PK.json b/public/intl/messages/ur-PK.json
index dbafa683..52a0d532 100644
--- a/public/intl/messages/ur-PK.json
+++ b/public/intl/messages/ur-PK.json
@@ -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,
diff --git a/public/intl/messages/vi-VN.json b/public/intl/messages/vi-VN.json
index 8c6e3152..8c87d639 100644
--- a/public/intl/messages/vi-VN.json
+++ b/public/intl/messages/vi-VN.json
@@ -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,
diff --git a/public/intl/messages/zh-CN.json b/public/intl/messages/zh-CN.json
index 9e825fc7..dc30074a 100644
--- a/public/intl/messages/zh-CN.json
+++ b/public/intl/messages/zh-CN.json
@@ -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,
diff --git a/public/intl/messages/zh-TW.json b/public/intl/messages/zh-TW.json
index dc669b8a..c13a31ce 100644
--- a/public/intl/messages/zh-TW.json
+++ b/public/intl/messages/zh-TW.json
@@ -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,
diff --git a/queries/admin/account/createAccount.js b/queries/admin/account/createAccount.js
index 2902e526..193ed719 100644
--- a/queries/admin/account/createAccount.js
+++ b/queries/admin/account/createAccount.js
@@ -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(
diff --git a/queries/admin/account/deleteAccount.js b/queries/admin/account/deleteAccount.js
index 242b851c..402b4111 100644
--- a/queries/admin/account/deleteAccount.js
+++ b/queries/admin/account/deleteAccount.js
@@ -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(
diff --git a/queries/admin/account/getAccountById.js b/queries/admin/account/getAccountById.js
index bb3ae85f..de2605e1 100644
--- a/queries/admin/account/getAccountById.js
+++ b/queries/admin/account/getAccountById.js
@@ -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(
diff --git a/queries/admin/account/getAccountByUsername.js b/queries/admin/account/getAccountByUsername.js
index 5e786a2a..d476c38e 100644
--- a/queries/admin/account/getAccountByUsername.js
+++ b/queries/admin/account/getAccountByUsername.js
@@ -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(
diff --git a/queries/admin/account/getAccounts.js b/queries/admin/account/getAccounts.js
index 647e3626..e6ebedf2 100644
--- a/queries/admin/account/getAccounts.js
+++ b/queries/admin/account/getAccounts.js
@@ -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(
diff --git a/queries/admin/account/updateAccount.js b/queries/admin/account/updateAccount.js
index 3fd252dd..b8d718f4 100644
--- a/queries/admin/account/updateAccount.js
+++ b/queries/admin/account/updateAccount.js
@@ -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(
diff --git a/queries/admin/website/createWebsite.js b/queries/admin/website/createWebsite.js
index a0b33a98..3cb6887f 100644
--- a/queries/admin/website/createWebsite.js
+++ b/queries/admin/website/createWebsite.js
@@ -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(
diff --git a/queries/admin/website/deleteWebsite.js b/queries/admin/website/deleteWebsite.js
index 0bdd3491..81cef845 100644
--- a/queries/admin/website/deleteWebsite.js
+++ b/queries/admin/website/deleteWebsite.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function deleteWebsite(website_id) {
return runQuery(
diff --git a/queries/admin/website/getAllWebsites.js b/queries/admin/website/getAllWebsites.js
index 5cc12cba..7e413fe8 100644
--- a/queries/admin/website/getAllWebsites.js
+++ b/queries/admin/website/getAllWebsites.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function getAllWebsites() {
let data = await runQuery(
diff --git a/queries/admin/website/getUserWebsites.js b/queries/admin/website/getUserWebsites.js
index 28619417..4cd75997 100644
--- a/queries/admin/website/getUserWebsites.js
+++ b/queries/admin/website/getUserWebsites.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function getUserWebsites(user_id) {
return runQuery(
diff --git a/queries/admin/website/getWebsiteById.js b/queries/admin/website/getWebsiteById.js
index ad2d9b11..8cf0f50f 100644
--- a/queries/admin/website/getWebsiteById.js
+++ b/queries/admin/website/getWebsiteById.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function getWebsiteById(website_id) {
return runQuery(
diff --git a/queries/admin/website/getWebsiteByShareId.js b/queries/admin/website/getWebsiteByShareId.js
index d6074e09..9fcc1ab3 100644
--- a/queries/admin/website/getWebsiteByShareId.js
+++ b/queries/admin/website/getWebsiteByShareId.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function getWebsiteByShareId(share_id) {
return runQuery(
diff --git a/queries/admin/website/getWebsiteByUuid.js b/queries/admin/website/getWebsiteByUuid.js
index 58ada3a3..36c41e67 100644
--- a/queries/admin/website/getWebsiteByUuid.js
+++ b/queries/admin/website/getWebsiteByUuid.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function getWebsiteByUuid(website_uuid) {
return runQuery(
diff --git a/queries/admin/website/resetWebsite.js b/queries/admin/website/resetWebsite.js
index 45ce2315..18f249b8 100644
--- a/queries/admin/website/resetWebsite.js
+++ b/queries/admin/website/resetWebsite.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function resetWebsite(website_id) {
return runQuery(prisma.$queryRaw`delete from session where website_id=${website_id}`);
diff --git a/queries/admin/website/updateWebsite.js b/queries/admin/website/updateWebsite.js
index 29561bb2..e2a16925 100644
--- a/queries/admin/website/updateWebsite.js
+++ b/queries/admin/website/updateWebsite.js
@@ -1,5 +1,4 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { prisma, runQuery } from 'lib/db';
export async function updateWebsite(website_id, data) {
return runQuery(
diff --git a/queries/analytics/event/getEventMetrics.js b/queries/analytics/event/getEventMetrics.js
index b0ec87b4..ff3fcf01 100644
--- a/queries/analytics/event/getEventMetrics.js
+++ b/queries/analytics/event/getEventMetrics.js
@@ -1,6 +1,22 @@
-import { getDateQuery, getFilterQuery, rawQuery } from 'lib/queries';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ getBetweenDatesClickhouse,
+ getDateQuery,
+ getDateQueryClickhouse,
+ getFilterQuery,
+ rawQuery,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+} from 'lib/db';
-export function getEventMetrics(
+export async function getEventMetrics(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(
website_id,
start_at,
end_at,
@@ -26,3 +42,30 @@ export function getEventMetrics(
params,
);
}
+
+async function clickhouseQuery(
+ website_id,
+ start_at,
+ end_at,
+ timezone = 'UTC',
+ unit = 'day',
+ filters = {},
+) {
+ const params = [website_id];
+
+ return rawQueryClickhouse(
+ `
+ select
+ event_value x,
+ ${getDateQueryClickhouse('created_at', unit, timezone)} t,
+ count(*) y
+ from event
+ where website_id= $1
+ and ${getBetweenDatesClickhouse('created_at', start_at, end_at)}
+ ${getFilterQuery('event', filters, params)}
+ group by x, t
+ order by t
+ `,
+ params,
+ );
+}
diff --git a/queries/analytics/event/getEvents.js b/queries/analytics/event/getEvents.js
index 9d8671db..059c8014 100644
--- a/queries/analytics/event/getEvents.js
+++ b/queries/analytics/event/getEvents.js
@@ -1,7 +1,20 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ rawQueryClickhouse,
+ getDateFormatClickhouse,
+ prisma,
+ runAnalyticsQuery,
+ runQuery,
+} from 'lib/db';
-export async function getEvents(websites, start_at) {
+export function getEvents(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+function relationalQuery(websites, start_at) {
return runQuery(
prisma.event.findMany({
where: {
@@ -17,3 +30,20 @@ export async function getEvents(websites, start_at) {
}),
);
}
+
+function clickhouseQuery(websites, start_at) {
+ return rawQueryClickhouse(
+ `
+ select
+ event_id,
+ website_id,
+ session_id,
+ created_at,
+ url,
+ event_type
+ from event
+ where website_id in (${websites.join[',']}
+ and created_at >= ${getDateFormatClickhouse(start_at)})
+ `,
+ );
+}
diff --git a/queries/analytics/event/saveEvent.js b/queries/analytics/event/saveEvent.js
index 8f5bf8d2..abb32cbb 100644
--- a/queries/analytics/event/saveEvent.js
+++ b/queries/analytics/event/saveEvent.js
@@ -1,8 +1,20 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
-import { URL_LENGTH } from 'lib/constants';
+import { CLICKHOUSE, RELATIONAL, URL_LENGTH } from 'lib/constants';
+import {
+ getDateFormatClickhouse,
+ prisma,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+ runQuery,
+} from 'lib/db';
-export async function saveEvent(website_id, session_id, url, event_type, event_value) {
+export async function saveEvent(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(website_id, { session_id, url, event_type, event_value }) {
return runQuery(
prisma.event.create({
data: {
@@ -15,3 +27,20 @@ export async function saveEvent(website_id, session_id, url, event_type, event_v
}),
);
}
+
+async function clickhouseQuery(website_id, { session_uuid, url, event_type, event_value }) {
+ const params = [
+ website_id,
+ session_uuid,
+ url?.substr(0, URL_LENGTH),
+ event_type?.substr(0, 50),
+ event_value?.substr(0, 50),
+ ];
+
+ return rawQueryClickhouse(
+ `
+ insert into umami_dev.event (created_at, website_id, session_uuid, url, event_type, event_value)
+ values (${getDateFormatClickhouse(new Date())}, $1, $2, $3, $4, $5);`,
+ params,
+ );
+}
diff --git a/queries/analytics/pageview/getPageviewMetrics.js b/queries/analytics/pageview/getPageviewMetrics.js
index a7233011..e7447375 100644
--- a/queries/analytics/pageview/getPageviewMetrics.js
+++ b/queries/analytics/pageview/getPageviewMetrics.js
@@ -1,6 +1,20 @@
-import { parseFilters, rawQuery } from 'lib/queries';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+ parseFilters,
+ rawQuery,
+ getBetweenDatesClickhouse,
+} from 'lib/db';
-export function getPageviewMetrics(website_id, start_at, end_at, column, table, filters = {}) {
+export async function getPageviewMetrics(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(website_id, start_at, end_at, column, table, filters = {}) {
const params = [website_id, start_at, end_at];
const { pageviewQuery, sessionQuery, eventQuery, joinSession } = parseFilters(
table,
@@ -15,13 +29,40 @@ export function getPageviewMetrics(website_id, start_at, end_at, column, table,
from ${table}
${joinSession}
where ${table}.website_id=$1
- and ${table}.created_at between $2 and $3
- ${pageviewQuery}
- ${joinSession && sessionQuery}
- ${eventQuery}
+ and ${table}.created_at between $2 and $3
+ ${pageviewQuery}
+ ${joinSession && sessionQuery}
+ ${eventQuery}
group by 1
order by 2 desc
`,
params,
);
}
+
+async function clickhouseQuery(website_id, start_at, end_at, column, table, filters = {}) {
+ const params = [website_id];
+ const { pageviewQuery, sessionQuery, eventQuery, joinSession } = parseFilters(
+ table,
+ column,
+ filters,
+ params,
+ 'session_uuid',
+ );
+
+ return rawQueryClickhouse(
+ `
+ select ${column} x, count(*) y
+ from ${table}
+ ${joinSession}
+ where ${table}.website_id= $1
+ and ${getBetweenDatesClickhouse(table + '.created_at', start_at, end_at)}
+ ${pageviewQuery}
+ ${joinSession && sessionQuery}
+ ${eventQuery}
+ group by x
+ order by y desc
+ `,
+ params,
+ );
+}
diff --git a/queries/analytics/pageview/getPageviewParams.js b/queries/analytics/pageview/getPageviewParams.js
new file mode 100644
index 00000000..fd25c77e
--- /dev/null
+++ b/queries/analytics/pageview/getPageviewParams.js
@@ -0,0 +1,48 @@
+import { getDatabase, parseFilters, rawQuery, runAnalyticsQuery } from 'lib/db';
+import { MYSQL, POSTGRESQL, CLICKHOUSE, RELATIONAL } from 'lib/constants';
+
+export async function getPageviewParams(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+function relationalQuery(param, website_id, start_at, end_at, column, table, filters = {}) {
+ const params = [param, website_id, start_at, end_at];
+ const { pageviewQuery, sessionQuery, eventQuery, joinSession } = parseFilters(
+ table,
+ column,
+ filters,
+ params,
+ );
+
+ let splitFn;
+ let db = getDatabase();
+ if (db === MYSQL) splitFn = 'substring_index';
+ if (db === POSTGRESQL) splitFn = 'split_part';
+ if (!splitFn) return Promise.reject(new Error('Unknown database.'));
+
+ return rawQuery(
+ `select * from (
+ select
+ url, ${splitFn}(${splitFn}(url, concat($1, '='), 2), '&', 1) param
+ from
+ pageview
+ ${joinSession}
+ where
+ ${table}.website_id=$2 and ${table}.created_at between $3 and $4
+ ${pageviewQuery}
+ ${joinSession && sessionQuery}
+ ${eventQuery}
+ group by 1, 2
+ order by 2 desc
+ ) q
+ where q.param <> ''`,
+ params,
+ );
+}
+
+function clickhouseQuery() {
+ return Promise.reject(new Error('Not implemented.'));
+}
diff --git a/queries/analytics/pageview/getPageviewStats.js b/queries/analytics/pageview/getPageviewStats.js
index c4b9ef23..0a320074 100644
--- a/queries/analytics/pageview/getPageviewStats.js
+++ b/queries/analytics/pageview/getPageviewStats.js
@@ -1,6 +1,23 @@
-import { parseFilters, rawQuery, getDateQuery } from 'lib/queries';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ getBetweenDatesClickhouse,
+ getDateQuery,
+ getDateQueryClickhouse,
+ getDateStringQueryClickhouse,
+ parseFilters,
+ rawQuery,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+} from 'lib/db';
-export function getPageviewStats(
+export async function getPageviewStats(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(
website_id,
start_at,
end_at,
@@ -8,6 +25,7 @@ export function getPageviewStats(
unit = 'day',
count = '*',
filters = {},
+ sessionKey = 'session_id',
) {
const params = [website_id, start_at, end_at];
const { pageviewQuery, sessionQuery, joinSession } = parseFilters(
@@ -19,20 +37,56 @@ export function getPageviewStats(
return rawQuery(
`
- select
- g.t as t,
- g.y as y
- from
- (select ${getDateQuery('pageview.created_at', unit, timezone)} t,
- count(${count}) y
+ select ${getDateQuery('pageview.created_at', unit, timezone)} t,
+ count(${count !== '*' ? `${count}${sessionKey}` : count}) y
from pageview
${joinSession}
where pageview.website_id=$1
- and pageview.created_at between $2 and $3
- ${pageviewQuery}
- ${sessionQuery}
- group by 1) g
- order by 1
+ and pageview.created_at between $2 and $3
+ ${pageviewQuery}
+ ${sessionQuery}
+ group by 1
+ `,
+ params,
+ );
+}
+
+async function clickhouseQuery(
+ website_id,
+ start_at,
+ end_at,
+ timezone = 'UTC',
+ unit = 'day',
+ count = '*',
+ filters = {},
+ sessionKey = 'session_uuid',
+) {
+ const params = [website_id];
+ const { pageviewQuery, sessionQuery, joinSession } = parseFilters(
+ 'pageview',
+ null,
+ filters,
+ params,
+ sessionKey,
+ );
+
+ return rawQueryClickhouse(
+ `
+ select
+ ${getDateStringQueryClickhouse('g.t', unit)} as t,
+ g.y as y
+ from
+ (select
+ ${getDateQueryClickhouse('created_at', unit, timezone)} t,
+ count(${count !== '*' ? `${count}${sessionKey}` : count}) y
+ from pageview
+ ${joinSession}
+ where pageview.website_id= $1
+ and ${getBetweenDatesClickhouse('pageview.created_at', start_at, end_at)}
+ ${pageviewQuery}
+ ${sessionQuery}
+ group by t) g
+ order by t
`,
params,
);
diff --git a/queries/analytics/pageview/getPageviews.js b/queries/analytics/pageview/getPageviews.js
index 8fffd539..d7b28611 100644
--- a/queries/analytics/pageview/getPageviews.js
+++ b/queries/analytics/pageview/getPageviews.js
@@ -1,7 +1,20 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ rawQueryClickhouse,
+ getDateFormatClickhouse,
+ prisma,
+ runAnalyticsQuery,
+ runQuery,
+} from 'lib/db';
-export async function getPageviews(websites, start_at) {
+export async function getPageviews(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(websites, start_at) {
return runQuery(
prisma.pageview.findMany({
where: {
@@ -17,3 +30,19 @@ export async function getPageviews(websites, start_at) {
}),
);
}
+
+async function clickhouseQuery(websites, start_at) {
+ return rawQueryClickhouse(
+ `
+ select
+ view_id,
+ website_id,
+ session_id,
+ created_at,
+ url
+ from pageview
+ where website_id in (${websites.join[',']}
+ and created_at >= ${getDateFormatClickhouse(start_at)})
+ `,
+ );
+}
diff --git a/queries/analytics/pageview/savePageView.js b/queries/analytics/pageview/savePageView.js
index 427c6143..72ab35fb 100644
--- a/queries/analytics/pageview/savePageView.js
+++ b/queries/analytics/pageview/savePageView.js
@@ -1,8 +1,20 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
-import { URL_LENGTH } from 'lib/constants';
+import { CLICKHOUSE, RELATIONAL, URL_LENGTH } from 'lib/constants';
+import {
+ getDateFormatClickhouse,
+ prisma,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+ runQuery,
+} from 'lib/db';
-export async function savePageView(website_id, session_id, url, referrer) {
+export async function savePageView(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(website_id, { session_id, url, referrer }) {
return runQuery(
prisma.pageview.create({
data: {
@@ -14,3 +26,19 @@ export async function savePageView(website_id, session_id, url, referrer) {
}),
);
}
+
+async function clickhouseQuery(website_id, { session_uuid, url, referrer }) {
+ const params = [
+ website_id,
+ session_uuid,
+ url?.substr(0, URL_LENGTH),
+ referrer?.substr(0, URL_LENGTH),
+ ];
+
+ return rawQueryClickhouse(
+ `
+ insert into umami_dev.pageview (created_at, website_id, session_uuid, url, referrer)
+ values (${getDateFormatClickhouse(new Date())}, $1, $2, $3, $4);`,
+ params,
+ );
+}
diff --git a/queries/analytics/session/createSession.js b/queries/analytics/session/createSession.js
index b6e8e950..22b41ebd 100644
--- a/queries/analytics/session/createSession.js
+++ b/queries/analytics/session/createSession.js
@@ -1,7 +1,21 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ getDateFormatClickhouse,
+ prisma,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+ runQuery,
+} from 'lib/db';
+import { getSessionByUuid } from 'queries';
-export async function createSession(website_id, data) {
+export async function createSession(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(website_id, data) {
return runQuery(
prisma.session.create({
data: {
@@ -14,3 +28,28 @@ export async function createSession(website_id, data) {
}),
);
}
+
+async function clickhouseQuery(
+ website_id,
+ { session_uuid, hostname, browser, os, screen, language, country, device },
+) {
+ const params = [
+ session_uuid,
+ website_id,
+ hostname,
+ browser,
+ os,
+ device,
+ screen,
+ language,
+ country ? country : null,
+ ];
+
+ await rawQueryClickhouse(
+ `insert into umami_dev.session (created_at, session_uuid, website_id, hostname, browser, os, device, screen, language, country)
+ values (${getDateFormatClickhouse(new Date())}, $1, $2, $3, $4, $5, $6, $7, $8, $9);`,
+ params,
+ );
+
+ return getSessionByUuid(session_uuid);
+}
diff --git a/queries/analytics/session/getSessionByUuid.js b/queries/analytics/session/getSessionByUuid.js
index 1d643efa..fde70e7f 100644
--- a/queries/analytics/session/getSessionByUuid.js
+++ b/queries/analytics/session/getSessionByUuid.js
@@ -1,7 +1,14 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import { rawQueryClickhouse, prisma, runAnalyticsQuery, runQuery } from 'lib/db';
-export async function getSessionByUuid(session_uuid) {
+export async function getSessionByUuid(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(session_uuid) {
return runQuery(
prisma.session.findUnique({
where: {
@@ -10,3 +17,26 @@ export async function getSessionByUuid(session_uuid) {
}),
);
}
+
+async function clickhouseQuery(session_uuid) {
+ const params = [session_uuid];
+
+ return rawQueryClickhouse(
+ `
+ select
+ session_uuid,
+ website_id,
+ created_at,
+ hostname,
+ browser,
+ os,
+ device,
+ screen,
+ "language",
+ country
+ from session
+ where session_uuid = $1
+ `,
+ params,
+ );
+}
diff --git a/queries/analytics/session/getSessionMetrics.js b/queries/analytics/session/getSessionMetrics.js
index 6ecbfecd..b9bbc708 100644
--- a/queries/analytics/session/getSessionMetrics.js
+++ b/queries/analytics/session/getSessionMetrics.js
@@ -1,6 +1,20 @@
-import { parseFilters, rawQuery } from 'lib/queries';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ getBetweenDatesClickhouse,
+ parseFilters,
+ rawQuery,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+} from 'lib/db';
-export function getSessionMetrics(website_id, start_at, end_at, field, filters = {}) {
+export async function getSessionMetrics(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(website_id, start_at, end_at, field, filters = {}) {
const params = [website_id, start_at, end_at];
const { pageviewQuery, sessionQuery, joinSession } = parseFilters(
'pageview',
@@ -28,3 +42,33 @@ export function getSessionMetrics(website_id, start_at, end_at, field, filters =
params,
);
}
+
+async function clickhouseQuery(website_id, start_at, end_at, field, filters = {}) {
+ const params = [website_id];
+ const { pageviewQuery, sessionQuery, joinSession } = parseFilters(
+ 'pageview',
+ null,
+ filters,
+ params,
+ 'session_uuid',
+ );
+
+ return rawQueryClickhouse(
+ `
+ select ${field} x, count(*) y
+ from session as x
+ where x.session_uuid in (
+ select pageview.session_uuid
+ from pageview
+ ${joinSession}
+ where pageview.website_id=$1
+ and ${getBetweenDatesClickhouse('pageview.created_at', start_at, end_at)}
+ ${pageviewQuery}
+ ${sessionQuery}
+ )
+ group by x
+ order by y desc
+ `,
+ params,
+ );
+}
diff --git a/queries/analytics/session/getSessions.js b/queries/analytics/session/getSessions.js
index 450d1ad2..09b55b8d 100644
--- a/queries/analytics/session/getSessions.js
+++ b/queries/analytics/session/getSessions.js
@@ -1,7 +1,20 @@
-import { runQuery } from 'lib/queries';
-import prisma from 'lib/db';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ getDateFormatClickhouse,
+ prisma,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+ runQuery,
+} from 'lib/db';
-export async function getSessions(websites, start_at) {
+export async function getSessions(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(websites, start_at) {
return runQuery(
prisma.session.findMany({
where: {
@@ -17,3 +30,25 @@ export async function getSessions(websites, start_at) {
}),
);
}
+
+async function clickhouseQuery(websites, start_at) {
+ return rawQueryClickhouse(
+ `
+ select
+ session_id,
+ session_uuid,
+ website_id,
+ created_at,
+ hostname,
+ browser,
+ os,
+ device,
+ screen,
+ "language",
+ country
+ from session
+ where website_id in (${websites.join[',']}
+ and created_at >= ${getDateFormatClickhouse(start_at)})
+ `,
+ );
+}
diff --git a/queries/analytics/stats/getActiveVisitors.js b/queries/analytics/stats/getActiveVisitors.js
index 3f923311..04884521 100644
--- a/queries/analytics/stats/getActiveVisitors.js
+++ b/queries/analytics/stats/getActiveVisitors.js
@@ -1,7 +1,15 @@
-import { rawQuery } from 'lib/queries';
import { subMinutes } from 'date-fns';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import { getDateFormatClickhouse, rawQuery, rawQueryClickhouse, runAnalyticsQuery } from 'lib/db';
-export function getActiveVisitors(website_id) {
+export async function getActiveVisitors(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(website_id) {
const date = subMinutes(new Date(), 5);
const params = [website_id, date];
@@ -9,9 +17,23 @@ export function getActiveVisitors(website_id) {
`
select count(distinct session_id) x
from pageview
- where website_id=$1
+ where website_id = $1
and created_at >= $2
`,
params,
);
}
+
+async function clickhouseQuery(website_id) {
+ const params = [website_id];
+
+ return rawQueryClickhouse(
+ `
+ select count(distinct session_uuid) x
+ from pageview
+ where website_id = $1
+ and created_at >= ${getDateFormatClickhouse(subMinutes(new Date(), 5))}
+ `,
+ params,
+ );
+}
diff --git a/queries/analytics/stats/getWebsiteStats.js b/queries/analytics/stats/getWebsiteStats.js
index b9c36d96..9328b85b 100644
--- a/queries/analytics/stats/getWebsiteStats.js
+++ b/queries/analytics/stats/getWebsiteStats.js
@@ -1,6 +1,23 @@
-import { parseFilters, rawQuery, getDateQuery, getTimestampInterval } from 'lib/queries';
+import { CLICKHOUSE, RELATIONAL } from 'lib/constants';
+import {
+ getDateQuery,
+ getBetweenDatesClickhouse,
+ getDateQueryClickhouse,
+ getTimestampInterval,
+ parseFilters,
+ rawQuery,
+ rawQueryClickhouse,
+ runAnalyticsQuery,
+} from 'lib/db';
-export function getWebsiteStats(website_id, start_at, end_at, filters = {}) {
+export async function getWebsiteStats(...args) {
+ return runAnalyticsQuery({
+ [`${RELATIONAL}`]: () => relationalQuery(...args),
+ [`${CLICKHOUSE}`]: () => clickhouseQuery(...args),
+ });
+}
+
+async function relationalQuery(website_id, start_at, end_at, filters = {}) {
const params = [website_id, start_at, end_at];
const { pageviewQuery, sessionQuery, joinSession } = parseFilters(
'pageview',
@@ -32,3 +49,39 @@ export function getWebsiteStats(website_id, start_at, end_at, filters = {}) {
params,
);
}
+
+async function clickhouseQuery(website_id, start_at, end_at, filters = {}) {
+ const params = [website_id];
+ const { pageviewQuery, sessionQuery, joinSession } = parseFilters(
+ 'pageview',
+ null,
+ filters,
+ params,
+ 'session_uuid',
+ );
+
+ return rawQueryClickhouse(
+ `
+ select
+ sum(t.c) as "pageviews",
+ count(distinct t.session_uuid) as "uniques",
+ sum(if(t.c = 1, 1, 0)) as "bounces",
+ sum(if(max_time < min_time + interval 1 hour, max_time-min_time, 0)) as "totaltime"
+ from (
+ select pageview.session_uuid,
+ ${getDateQueryClickhouse('pageview.created_at', 'day')} time_series,
+ count(*) c,
+ min(created_at) min_time,
+ max(created_at) max_time
+ from pageview
+ ${joinSession}
+ where pageview.website_id = $1
+ and ${getBetweenDatesClickhouse('pageview.created_at', start_at, end_at)}
+ ${pageviewQuery}
+ ${sessionQuery}
+ group by pageview.session_uuid, time_series
+ ) t;
+ `,
+ params,
+ );
+}
diff --git a/queries/index.js b/queries/index.js
index a3ea9d57..517307f6 100644
--- a/queries/index.js
+++ b/queries/index.js
@@ -17,6 +17,7 @@ import { getEventMetrics } from './analytics/event/getEventMetrics';
import { getEvents } from './analytics/event/getEvents';
import { saveEvent } from './analytics/event/saveEvent';
import { getPageviewMetrics } from './analytics/pageview/getPageviewMetrics';
+import { getPageviewParams } from './analytics/pageview/getPageviewParams';
import { getPageviews } from './analytics/pageview/getPageviews';
import { getPageviewStats } from './analytics/pageview/getPageviewStats';
import { savePageView } from './analytics/pageview/savePageView';
@@ -48,6 +49,7 @@ export {
getEvents,
saveEvent,
getPageviewMetrics,
+ getPageviewParams,
getPageviews,
getPageviewStats,
savePageView,
diff --git a/yarn.lock b/yarn.lock
index 1668978f..144118b7 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1933,6 +1933,14 @@
resolved "https://registry.npmjs.org/@vue/shared/-/shared-3.2.36.tgz"
integrity sha512-JtB41wXl7Au3+Nl3gD16Cfpj7k/6aCroZ6BbOiCMFCMvrOpkg/qQUXTso2XowaNqBbnkuGHurLAqkLBxNGc1hQ==
+JSONStream@1.3.4:
+ version "1.3.4"
+ resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.4.tgz#615bb2adb0cd34c8f4c447b5f6512fa1d8f16a2e"
+ integrity sha512-Y7vfi3I5oMOYIr+WxV8NZxDSwcbNgzdKYsTNInmycOq9bUYwGg9ryu57Wg5NLmCjqdFPNUmpMBo3kSJN9tCbXg==
+ dependencies:
+ jsonparse "^1.2.0"
+ through ">=2.2.7 <3"
+
acorn-dynamic-import@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz"
@@ -1985,7 +1993,7 @@ ajv-keywords@^5.0.0:
dependencies:
fast-deep-equal "^3.1.3"
-ajv@^6.10.0, ajv@^6.12.4:
+ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -2107,6 +2115,18 @@ arrify@^1.0.1:
resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==
+asn1@~0.2.3:
+ version "0.2.6"
+ resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d"
+ integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==
+ dependencies:
+ safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+ integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==
+
ast-types-flow@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad"
@@ -2117,6 +2137,11 @@ astral-regex@^2.0.0:
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31"
integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==
+asynckit@^0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+ integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
+
at-least-node@^1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz"
@@ -2134,6 +2159,16 @@ autoprefixer@^10.4.4:
picocolors "^1.0.0"
postcss-value-parser "^4.2.0"
+aws-sign2@~0.7.0:
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+ integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==
+
+aws4@^1.8.0:
+ version "1.11.0"
+ resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
+ integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
+
axe-core@^4.4.2:
version "4.4.3"
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.3.tgz#11c74d23d5013c0fa5d183796729bc3482bd2f6f"
@@ -2201,6 +2236,13 @@ balanced-match@^2.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9"
integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==
+bcrypt-pbkdf@^1.0.0:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+ integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==
+ dependencies:
+ tweetnacl "^0.14.3"
+
bcryptjs@^2.4.3:
version "2.4.3"
resolved "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz"
@@ -2325,6 +2367,11 @@ caniuse-lite@^1.0.30001313, caniuse-lite@^1.0.30001317, caniuse-lite@^1.0.300013
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001356.tgz"
integrity sha512-/30854bktMLhxtjieIxsrJBfs2gTM1pel6MXKF3K+RdIVJZcsn2A2QdhsuR4/p9+R204fZw0zCBBhktX8xWuyQ==
+caseless@~0.12.0:
+ version "0.12.0"
+ resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+ integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==
+
chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
@@ -2400,6 +2447,20 @@ cli-truncate@2.1.0, cli-truncate@^2.1.0:
slice-ansi "^3.0.0"
string-width "^4.2.0"
+clickhouse@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/clickhouse/-/clickhouse-2.5.0.tgz#29cece9aeb2e4f449ffb75933f32725a8f7798b3"
+ integrity sha512-3eszr5FUDnApZDCQOnpHVmNk6opTnzDNdZyG8n3MF1kf/dts47e7o2DbKC2xEG22orGMski1Flvf1J6nkUhvZA==
+ dependencies:
+ JSONStream "1.3.4"
+ lodash "4.17.21"
+ querystring "0.2.0"
+ request "2.88.0"
+ stream2asynciter "1.0.3"
+ through "2.3.8"
+ tsv "0.2.0"
+ uuid "3.4.0"
+
clone-regexp@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-2.2.0.tgz#7d65e00885cd8796405c35a737e7a86b7429e36f"
@@ -2446,6 +2507,13 @@ colorette@^2.0.16:
resolved "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz"
integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==
+combined-stream@^1.0.6, combined-stream@~1.0.6:
+ version "1.0.8"
+ resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+ integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+ dependencies:
+ delayed-stream "~1.0.0"
+
commander@2, commander@^2.20.0:
version "2.20.3"
resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
@@ -2491,6 +2559,11 @@ core-js-pure@^3.20.2:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.23.4.tgz#aba5c7fb297063444f6bf93afb0362151679a012"
integrity sha512-lizxkcgj3XDmi7TUBFe+bQ1vNpD5E4t76BrBWI3HdUxdw/Mq1VF4CkiHzIKyieECKtcODK2asJttoofEeUKICQ==
+core-util-is@1.0.2:
+ version "1.0.2"
+ resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+ integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==
+
cors@^2.8.5:
version "2.8.5"
resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz"
@@ -2700,6 +2773,13 @@ damerau-levenshtein@^1.0.8:
resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7"
integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==
+dashdash@^1.12.0:
+ version "1.14.1"
+ resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+ integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==
+ dependencies:
+ assert-plus "^1.0.0"
+
data-uri-to-buffer@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz#b5db46aea50f6176428ac05b73be39a57701a64b"
@@ -2798,6 +2878,11 @@ del@^6.0.0:
rimraf "^3.0.2"
slash "^3.0.0"
+delayed-stream@~1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+ integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
+
detect-browser@^5.2.0:
version "5.3.0"
resolved "https://registry.npmjs.org/detect-browser/-/detect-browser-5.3.0.tgz"
@@ -2864,6 +2949,14 @@ dotenv@^10.0.0:
resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz"
integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q==
+ecc-jsbn@~0.1.1:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+ integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==
+ dependencies:
+ jsbn "~0.1.0"
+ safer-buffer "^2.1.0"
+
electron-to-chromium@^1.4.118, electron-to-chromium@^1.4.84:
version "1.4.143"
resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.143.tgz"
@@ -3241,6 +3334,11 @@ execall@^2.0.0:
dependencies:
clone-regexp "^2.1.0"
+extend@~3.0.2:
+ version "3.0.2"
+ resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+ integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
extract-react-intl-messages@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/extract-react-intl-messages/-/extract-react-intl-messages-4.1.1.tgz"
@@ -3262,6 +3360,16 @@ extract-react-intl-messages@^4.1.1:
sort-keys "^4.0.0"
write-json-file "^4.3.0"
+extsprintf@1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+ integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==
+
+extsprintf@^1.2.0:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07"
+ integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==
+
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
@@ -3368,6 +3476,20 @@ flatted@^3.1.0:
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2"
integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==
+forever-agent@~0.6.1:
+ version "0.6.1"
+ resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+ integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==
+
+form-data@~2.3.2:
+ version "2.3.3"
+ resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+ integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+ dependencies:
+ asynckit "^0.4.0"
+ combined-stream "^1.0.6"
+ mime-types "^2.1.12"
+
formdata-polyfill@^4.0.10:
version "4.0.10"
resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423"
@@ -3491,6 +3613,13 @@ get-symbol-description@^1.0.0:
call-bind "^1.0.2"
get-intrinsic "^1.1.1"
+getpass@^0.1.1:
+ version "0.1.7"
+ resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+ integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==
+ dependencies:
+ assert-plus "^1.0.0"
+
glob-parent@^5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
@@ -3577,6 +3706,19 @@ graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4:
resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz"
integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
+har-schema@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+ integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==
+
+har-validator@~5.1.0:
+ version "5.1.5"
+ resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
+ integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
+ dependencies:
+ ajv "^6.12.3"
+ har-schema "^2.0.0"
+
hard-rejection@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
@@ -3647,6 +3789,15 @@ html-tags@^3.2.0:
resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961"
integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==
+http-signature@~1.2.0:
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+ integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==
+ dependencies:
+ assert-plus "^1.0.0"
+ jsprim "^1.2.2"
+ sshpk "^1.7.0"
+
human-signals@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
@@ -3921,7 +4072,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3:
dependencies:
has-symbols "^1.0.2"
-is-typedarray@^1.0.0:
+is-typedarray@^1.0.0, is-typedarray@~1.0.0:
version "1.0.0"
resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
@@ -3948,6 +4099,11 @@ isexe@^2.0.0:
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
+isstream@~0.1.2:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+ integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==
+
jest-worker@^26.2.1:
version "26.6.2"
resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz"
@@ -3977,6 +4133,11 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
+jsbn@~0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+ integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==
+
jsesc@^2.5.1:
version "2.5.2"
resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
@@ -4007,6 +4168,11 @@ json-schema-traverse@^1.0.0:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
+json-schema@0.4.0:
+ version "0.4.0"
+ resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
+ integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
+
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
@@ -4019,6 +4185,11 @@ json-stable-stringify@^1.0.1:
dependencies:
jsonify "~0.0.0"
+json-stringify-safe@~5.0.1:
+ version "5.0.1"
+ resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
+ integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==
+
json5@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
@@ -4047,7 +4218,30 @@ jsonify@~0.0.0:
resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
integrity sha512-trvBk1ki43VZptdBI5rIlG4YOzyeH/WefQt5rj1grasPn4iiZWKet8nkgc4GlsAylaztn0qZfUYOiTsASJFdNA==
-"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.1:
+jsonparse@^1.2.0:
+ version "1.3.1"
+ resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280"
+ integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==
+
+jsprim@^1.2.2:
+ version "1.4.2"
+ resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb"
+ integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==
+ dependencies:
+ assert-plus "1.0.0"
+ extsprintf "1.3.0"
+ json-schema "0.4.0"
+ verror "1.10.0"
+
+"jsx-ast-utils@^2.4.1 || ^3.0.0":
+ version "3.3.0"
+ resolved "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.0.tgz"
+ integrity sha512-XzO9luP6L0xkxwhIJMTJQpZo/eeN60K08jHdexfD569AGxeNug6UketeHXEhROoM8aR7EcUoOQmIhcJQjcuq8Q==
+ dependencies:
+ array-includes "^3.1.4"
+ object.assign "^4.1.2"
+
+jsx-ast-utils@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.2.tgz#afe5efe4332cd3515c065072bd4d6b0aa22152bd"
integrity sha512-4ZCADZHRkno244xlNnn4AOG6sRQ7iBZ5BbgZ4vW4y5IZw7cVUD1PPeblm1xx/nfmMxPdt/LHsXZW8z/j58+l9Q==
@@ -4201,7 +4395,7 @@ lodash.truncate@^4.4.2:
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==
-lodash@^4.17.21:
+lodash@4.17.21, lodash@^4.17.21:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
@@ -4343,6 +4537,18 @@ micromatch@^4.0.4, micromatch@^4.0.5:
braces "^3.0.2"
picomatch "^2.3.1"
+mime-db@1.52.0:
+ version "1.52.0"
+ resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
+ integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
+
+mime-types@^2.1.12, mime-types@~2.1.19:
+ version "2.1.35"
+ resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
+ integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
+ dependencies:
+ mime-db "1.52.0"
+
mimic-fn@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
@@ -4550,6 +4756,11 @@ nth-check@^2.0.1:
dependencies:
boolbase "^1.0.0"
+oauth-sign@~0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+ integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
object-assign@^4, object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
@@ -4762,6 +4973,11 @@ path-type@^4.0.0:
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
+performance-now@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+ integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==
+
picocolors@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
@@ -5149,11 +5365,31 @@ prop-types@^15.7.2, prop-types@^15.8.1:
object-assign "^4.1.1"
react-is "^16.13.1"
+psl@^1.1.24:
+ version "1.9.0"
+ resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7"
+ integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==
+
+punycode@^1.4.1:
+ version "1.4.1"
+ resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+ integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==
+
punycode@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+qs@~6.5.2:
+ version "6.5.3"
+ resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
+ integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
+
+querystring@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+ integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==
+
queue-microtask@^1.2.2:
version "1.2.3"
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
@@ -5410,6 +5646,32 @@ request-ip@^2.1.3:
dependencies:
is_js "^0.9.0"
+request@2.88.0:
+ version "2.88.0"
+ resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+ integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
+ dependencies:
+ aws-sign2 "~0.7.0"
+ aws4 "^1.8.0"
+ caseless "~0.12.0"
+ combined-stream "~1.0.6"
+ extend "~3.0.2"
+ forever-agent "~0.6.1"
+ form-data "~2.3.2"
+ har-validator "~5.1.0"
+ http-signature "~1.2.0"
+ is-typedarray "~1.0.0"
+ isstream "~0.1.2"
+ json-stringify-safe "~5.0.1"
+ mime-types "~2.1.19"
+ oauth-sign "~0.9.0"
+ performance-now "^2.1.0"
+ qs "~6.5.2"
+ safe-buffer "^5.1.2"
+ tough-cookie "~2.4.3"
+ tunnel-agent "^0.6.0"
+ uuid "^3.3.2"
+
require-from-string@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909"
@@ -5518,7 +5780,7 @@ rxjs@^7.5.1:
dependencies:
tslib "^2.1.0"
-safe-buffer@^5.1.0:
+safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2:
version "5.2.1"
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
@@ -5528,6 +5790,11 @@ safe-buffer@~5.1.1:
resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+ integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz"
@@ -5733,11 +6000,31 @@ sprintf-js@~1.0.2:
resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+sshpk@^1.7.0:
+ version "1.17.0"
+ resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5"
+ integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==
+ dependencies:
+ asn1 "~0.2.3"
+ assert-plus "^1.0.0"
+ bcrypt-pbkdf "^1.0.0"
+ dashdash "^1.12.0"
+ ecc-jsbn "~0.1.1"
+ getpass "^0.1.1"
+ jsbn "~0.1.0"
+ safer-buffer "^2.0.2"
+ tweetnacl "~0.14.0"
+
stable@^0.1.8:
version "0.1.8"
resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz"
integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
+stream2asynciter@1.0.3:
+ version "1.0.3"
+ resolved "https://registry.yarnpkg.com/stream2asynciter/-/stream2asynciter-1.0.3.tgz#7ba9046846c8b1caf36ec30d64a73514f7f44c5a"
+ integrity sha512-9/dEZW+LQjuW6ub5hmWi4n9Pn8W8qA8k7NAE1isecesA164e73xTdy1CJ3S9o9YS+O21HuiK7T+4uS7FgKDy4w==
+
string-argv@0.3.1:
version "0.3.1"
resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz"
@@ -6020,7 +6307,7 @@ thenby@^1.3.4:
resolved "https://registry.npmjs.org/thenby/-/thenby-1.3.4.tgz"
integrity sha512-89Gi5raiWA3QZ4b2ePcEwswC3me9JIg+ToSgtE0JWeCynLnLxNr/f9G+xfo9K+Oj4AFdom8YNJjibIARTJmapQ==
-through@^2.3.8:
+through@2.3.8, "through@>=2.2.7 <3", through@^2.3.8:
version "2.3.8"
resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
@@ -6061,6 +6348,14 @@ topojson-client@^3.1.0:
dependencies:
commander "2"
+tough-cookie@~2.4.3:
+ version "2.4.3"
+ resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+ integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
+ dependencies:
+ psl "^1.1.24"
+ punycode "^1.4.1"
+
trim-newlines@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144"
@@ -6093,6 +6388,23 @@ tsutils@^3.21.0:
dependencies:
tslib "^1.8.1"
+tsv@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/tsv/-/tsv-0.2.0.tgz#92869a3cb5f50332f3dc90fca82be667db6f72d6"
+ integrity sha512-GG6xbOP85giXXom0dS6z9uyDsxktznjpa1AuDlPrIXDqDnbhjr9Vk6Us8iz6U1nENL4CPS2jZDvIjEdaZsmc4Q==
+
+tunnel-agent@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+ integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==
+ dependencies:
+ safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+ version "0.14.5"
+ resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+ integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==
+
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
@@ -6225,6 +6537,11 @@ util-deprecate@^1.0.2:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
+uuid@3.4.0, uuid@^3.3.2:
+ version "3.4.0"
+ resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
+ integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
+
uuid@^7.0.3:
version "7.0.3"
resolved "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz"
@@ -6253,6 +6570,15 @@ vary@^1:
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+verror@1.10.0:
+ version "1.10.0"
+ resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+ integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==
+ dependencies:
+ assert-plus "^1.0.0"
+ core-util-is "1.0.2"
+ extsprintf "^1.2.0"
+
vue@^3.2.23:
version "3.2.36"
resolved "https://registry.npmjs.org/vue/-/vue-3.2.36.tgz"