diff --git a/package.json b/package.json index c8ed652193..c1aaf410e7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "umami", - "version": "2.13.1", + "version": "2.13.2", "description": "A simple, fast, privacy-focused alternative to Google Analytics.", "author": "Umami Software, Inc. ", "license": "MIT", diff --git a/public/intl/messages/ca-ES.json b/public/intl/messages/ca-ES.json index ccc4988908..69b69e4354 100644 --- a/public/intl/messages/ca-ES.json +++ b/public/intl/messages/ca-ES.json @@ -1180,7 +1180,7 @@ "label.team-manager": [ { "type": 0, - "value": "Responsable d'Equip" + "value": "Responsable d'equip" } ], "label.team-member": [ diff --git a/public/intl/messages/de-DE.json b/public/intl/messages/de-DE.json index 84bc60e136..84e7364c53 100644 --- a/public/intl/messages/de-DE.json +++ b/public/intl/messages/de-DE.json @@ -404,19 +404,19 @@ "label.entry": [ { "type": 0, - "value": "Eintrags-URL" + "value": "Eingangs-URL" } ], "label.event": [ { "type": 0, - "value": "Event" + "value": "Ereigniss" } ], "label.event-data": [ { "type": 0, - "value": "Eventdaten" + "value": "Ereignissdaten" } ], "label.events": [ @@ -476,19 +476,19 @@ "label.first-seen": [ { "type": 0, - "value": "First seen" + "value": "Erstmalig gesehen" } ], "label.funnel": [ { "type": 0, - "value": "Funnel" + "value": "Trichter" } ], "label.funnel-description": [ { "type": 0, - "value": "Verstehe die Konversions- und Abbruchrate der Nutzer." + "value": "Verstehen Sie die Konversions- und Absprungrate Ihrer Nutzer." } ], "label.goal": [ @@ -542,7 +542,7 @@ "label.insights-description": [ { "type": 0, - "value": "Vertiefen Sie Ihre Daten mit Hilfe von Segmenten und Filtern." + "value": "Vertiefen Sie sich mit Hilfe von Segmenten und Filtern in Ihre Daten." } ], "label.is": [ @@ -590,7 +590,7 @@ "label.journey-description": [ { "type": 0, - "value": "Verstehe, wie Nutzer auf der Webseite navigieren" + "value": "Verstehen Sie, wie Nutzer auf Ihrer Website navigieren." } ], "label.language": [ @@ -656,7 +656,7 @@ "label.last-seen": [ { "type": 0, - "value": "Last seen" + "value": "Zuletzt gesehen" } ], "label.leave": [ @@ -752,7 +752,7 @@ "label.my-websites": [ { "type": 0, - "value": "Meine Webseiten" + "value": "Meine Websites" } ], "label.name": [ @@ -876,13 +876,13 @@ "label.path": [ { "type": 0, - "value": "Path" + "value": "Pfad" } ], "label.paths": [ { "type": 0, - "value": "Paths" + "value": "Pfade" } ], "label.powered-by": [ @@ -898,7 +898,7 @@ "label.previous": [ { "type": 0, - "value": "Vorheriges" + "value": "Vorherig" } ], "label.previous-period": [ @@ -922,7 +922,7 @@ "label.properties": [ { "type": 0, - "value": "Properties" + "value": "Eigenschaften" } ], "label.property": [ @@ -958,13 +958,13 @@ "label.referrer": [ { "type": 0, - "value": "Referrer" + "value": "Übermittler" } ], "label.referrers": [ { "type": 0, - "value": "Referrer" + "value": "Übermittler" } ], "label.refresh": [ @@ -1030,7 +1030,7 @@ "label.retention": [ { "type": 0, - "value": "Bewahrung" + "value": "Erhalt" } ], "label.retention-description": [ @@ -1042,19 +1042,19 @@ "label.revenue": [ { "type": 0, - "value": "Revenue" + "value": "Umsatz" } ], "label.revenue-description": [ { "type": 0, - "value": "Look into your revenue across time." + "value": "Haben Sie einen Blick auf Ihre Umsätze im Laufe der Zeit." } ], "label.revenue-property": [ { "type": 0, - "value": "Revenue Property" + "value": "Umsatzeigenschaften" } ], "label.role": [ @@ -1108,13 +1108,13 @@ "label.select-website": [ { "type": 0, - "value": "Webseite auswählen" + "value": "Website auswählen" } ], "label.session": [ { "type": 0, - "value": "Session" + "value": "Sitzung" } ], "label.sessions": [ @@ -1204,7 +1204,7 @@ "label.team-view-only": [ { "type": 0, - "value": "Nur für Team sichtbar" + "value": "Nur für Team-Mitglieder sichtbar" } ], "label.team-websites": [ @@ -1288,7 +1288,7 @@ "label.transactions": [ { "type": 0, - "value": "Transactions" + "value": "Transaktionen" } ], "label.transfer": [ @@ -1318,19 +1318,19 @@ "label.unique": [ { "type": 0, - "value": "Eindeutig" + "value": "Einzigartig" } ], "label.unique-visitors": [ { "type": 0, - "value": "Eindeutige Besucher" + "value": "Einzigartige Besucher" } ], "label.uniqueCustomers": [ { "type": 0, - "value": "Unique Customers" + "value": "Einzigartige Kunden" } ], "label.unknown": [ @@ -1372,7 +1372,7 @@ "label.user-property": [ { "type": 0, - "value": "User Property" + "value": "Benutzereigenschaften" } ], "label.username": [ @@ -1396,7 +1396,7 @@ "label.utm-description": [ { "type": 0, - "value": "Tracke deine Kampagnen mit UTM parameterns." + "value": "Tracken Sie Ihre Kampagnen mit UTM Parametern." } ], "label.value": [ @@ -1456,19 +1456,19 @@ "label.website": [ { "type": 0, - "value": "Webseite" + "value": "Website" } ], "label.website-id": [ { "type": 0, - "value": "Webseiten-ID" + "value": "Website-ID" } ], "label.websites": [ { "type": 0, - "value": "Webseiten" + "value": "Websites" } ], "label.window": [ @@ -1596,7 +1596,7 @@ "message.delete-team-warning": [ { "type": 0, - "value": "Ein Team zu löschen, wird auch alle Team-Webseiten löschen." + "value": "Ein Team zu löschen, wird auch alle Team-Websites löschen." } ], "message.delete-website-warning": [ @@ -1780,25 +1780,25 @@ "message.transfer-team-website-to-user": [ { "type": 0, - "value": "Diese Webseite zu deinem Account transferieren?" + "value": "Diese Website zu Ihrem Account transferieren?" } ], "message.transfer-user-website-to-team": [ { "type": 0, - "value": "Wähle ein Team aus, zu dem die Webseite transferiert werden soll." + "value": "Wählen Sie ein Team aus, zu dem die Website transferiert werden soll." } ], "message.transfer-website": [ { "type": 0, - "value": "Übertrage die Eigentümerrechte zu deinem Account oder einem anderen Team." + "value": "Übertragen Sie die Eigentümerrechte zu Ihrem Account oder einem anderen Team." } ], "message.triggered-event": [ { "type": 0, - "value": "Ausgelöstes Event" + "value": "Ausgelöstes Ereigniss" } ], "message.user-deleted": [ @@ -1810,7 +1810,7 @@ "message.viewed-page": [ { "type": 0, - "value": "Besuchte Seite" + "value": "Seite besucht" } ], "message.visitor-log": [ diff --git a/public/intl/messages/ko-KR.json b/public/intl/messages/ko-KR.json index 9f6520ea40..42a984191f 100644 --- a/public/intl/messages/ko-KR.json +++ b/public/intl/messages/ko-KR.json @@ -8,13 +8,13 @@ "label.actions": [ { "type": 0, - "value": "액션" + "value": "동작" } ], "label.activity": [ { "type": 0, - "value": "활동 기록" + "value": "활동" } ], "label.add": [ @@ -128,7 +128,7 @@ "label.change-password": [ { "type": 0, - "value": "비밀번호 변경하기" + "value": "비밀번호 변경" } ], "label.cities": [ @@ -200,25 +200,25 @@ "label.create": [ { "type": 0, - "value": "생성" + "value": "만들기" } ], "label.create-report": [ { "type": 0, - "value": "리포트 생성" + "value": "보고서 만들기" } ], "label.create-team": [ { "type": 0, - "value": "팀 생성" + "value": "팀 만들기" } ], "label.create-user": [ { "type": 0, - "value": "사용자 생성" + "value": "사용자 만들기" } ], "label.created": [ @@ -296,7 +296,7 @@ "label.delete-report": [ { "type": 0, - "value": "리포트 삭제" + "value": "보고서 삭제" } ], "label.delete-team": [ @@ -326,13 +326,13 @@ "label.desktop": [ { "type": 0, - "value": "데스크탑" + "value": "데스크톱" } ], "label.details": [ { "type": 0, - "value": "세부 사항" + "value": "세부 정보" } ], "label.device": [ @@ -386,7 +386,7 @@ "label.edit-member": [ { "type": 0, - "value": "회원 편집" + "value": "멤버 편집" } ], "label.enable-share-url": [ @@ -398,7 +398,7 @@ "label.end-step": [ { "type": 0, - "value": "종료 단계" + "value": "마지막 단계" } ], "label.entry": [ @@ -458,7 +458,7 @@ "label.filter-combined": [ { "type": 0, - "value": "합쳐서 보기" + "value": "합쳐 보기" } ], "label.filter-raw": [ @@ -476,7 +476,7 @@ "label.first-seen": [ { "type": 0, - "value": "First seen" + "value": "첫 접속" } ], "label.funnel": [ @@ -506,7 +506,7 @@ "label.goals-description": [ { "type": 0, - "value": "페이지뷰 및 이벤트 목표를 추적합니다." + "value": "페이지 조회 및 이벤트 목표를 추적합니다." } ], "label.greater-than": [ @@ -572,13 +572,13 @@ "label.join": [ { "type": 0, - "value": "가입" + "value": "가입하기" } ], "label.join-team": [ { "type": 0, - "value": "팀 가입" + "value": "팀 가입하기" } ], "label.journey": [ @@ -614,7 +614,7 @@ "label.last-days": [ { "type": 0, - "value": "최근 " + "value": "지난 " }, { "type": 1, @@ -622,13 +622,13 @@ }, { "type": 0, - "value": " 일" + "value": "일" } ], "label.last-hours": [ { "type": 0, - "value": "최근 " + "value": "지난 " }, { "type": 1, @@ -636,13 +636,13 @@ }, { "type": 0, - "value": " 시간" + "value": "시간" } ], "label.last-months": [ { "type": 0, - "value": "최근 " + "value": "지난 " }, { "type": 1, @@ -650,13 +650,13 @@ }, { "type": 0, - "value": " 개월" + "value": "개월" } ], "label.last-seen": [ { "type": 0, - "value": "Last seen" + "value": "마지막 접속" } ], "label.leave": [ @@ -780,31 +780,7 @@ }, { "type": 0, - "value": " " - }, - { - "offset": 0, - "options": { - "one": { - "value": [ - { - "type": 0, - "value": "record" - } - ] - }, - "other": { - "value": [ - { - "type": 0, - "value": "레코드" - } - ] - } - }, - "pluralType": "cardinal", - "type": 6, - "value": "x" + "value": "개 레코드" } ], "label.ok": [ @@ -816,7 +792,7 @@ "label.os": [ { "type": 0, - "value": "운영체제" + "value": "운영 체제" } ], "label.overview": [ @@ -832,13 +808,9 @@ } ], "label.page-of": [ - { - "type": 1, - "value": "total" - }, { "type": 0, - "value": " 중 " + "value": "페이지 " }, { "type": 1, @@ -846,13 +818,17 @@ }, { "type": 0, - "value": " 페이지" + "value": "/" + }, + { + "type": 1, + "value": "total" } ], "label.page-views": [ { "type": 0, - "value": "페이지 뷰" + "value": "페이지 조회" } ], "label.pageTitle": [ @@ -876,27 +852,23 @@ "label.path": [ { "type": 0, - "value": "Path" + "value": "패스" } ], "label.paths": [ { "type": 0, - "value": "Paths" + "value": "패스" } ], "label.powered-by": [ { "type": 0, - "value": "이 시스템은 " + "value": "Powered by " }, { "type": 1, "value": "name" - }, - { - "type": 0, - "value": "에서 구동되고 있습니다." } ], "label.previous": [ @@ -926,7 +898,7 @@ "label.properties": [ { "type": 0, - "value": "Properties" + "value": "속성" } ], "label.property": [ @@ -950,7 +922,7 @@ "label.query-parameters": [ { "type": 0, - "value": "쿼리 매개변수" + "value": "쿼리 매개 변수" } ], "label.realtime": [ @@ -974,7 +946,7 @@ "label.refresh": [ { "type": 0, - "value": "새로고침" + "value": "새로 고침" } ], "label.regenerate": [ @@ -1010,7 +982,7 @@ "label.reports": [ { "type": 0, - "value": "리포트" + "value": "보고서" } ], "label.required": [ @@ -1022,7 +994,7 @@ "label.reset": [ { "type": 0, - "value": "리셋" + "value": "초기화" } ], "label.reset-website": [ @@ -1046,19 +1018,19 @@ "label.revenue": [ { "type": 0, - "value": "Revenue" + "value": "수익" } ], "label.revenue-description": [ { "type": 0, - "value": "Look into your revenue across time." + "value": "시간대별 수익을 살펴보세요." } ], "label.revenue-property": [ { "type": 0, - "value": "Revenue Property" + "value": "수익 속성" } ], "label.role": [ @@ -1082,7 +1054,7 @@ "label.screens": [ { "type": 0, - "value": "스크린" + "value": "화면" } ], "label.search": [ @@ -1118,7 +1090,7 @@ "label.session": [ { "type": 0, - "value": "Session" + "value": "세션" } ], "label.sessions": [ @@ -1280,7 +1252,7 @@ "label.total-records": [ { "type": 0, - "value": "총 레코드" + "value": "전체 레코드" } ], "label.tracking-code": [ @@ -1292,7 +1264,7 @@ "label.transactions": [ { "type": 0, - "value": "Transactions" + "value": "거래" } ], "label.transfer": [ @@ -1328,13 +1300,13 @@ "label.unique-visitors": [ { "type": 0, - "value": "순방문자(UV)" + "value": "고유 방문자" } ], "label.uniqueCustomers": [ { "type": 0, - "value": "Unique Customers" + "value": "고유 고객" } ], "label.unknown": [ @@ -1376,13 +1348,13 @@ "label.user-property": [ { "type": 0, - "value": "User Property" + "value": "사용자 속성" } ], "label.username": [ { "type": 0, - "value": "사용자명" + "value": "사용자 이름" } ], "label.users": [ @@ -1418,7 +1390,7 @@ "label.view-details": [ { "type": 0, - "value": "상세보기" + "value": "자세히 보기" } ], "label.view-only": [ @@ -1430,13 +1402,13 @@ "label.views": [ { "type": 0, - "value": "조회수" + "value": "조회" } ], "label.views-per-visit": [ { "type": 0, - "value": "방문당 조회수" + "value": "방문당 조회" } ], "label.visit-duration": [ @@ -1448,7 +1420,7 @@ "label.visitors": [ { "type": 0, - "value": "방문객" + "value": "방문자" } ], "label.visits": [ @@ -1498,17 +1470,21 @@ }, { "type": 0, - "value": "을(를) 입력하십시오." + "value": "을(를) 입력하세요." } ], "message.active-users": [ + { + "type": 0, + "value": "현재 방문자 " + }, { "type": 1, "value": "x" }, { "type": 0, - "value": "명의 사용자가 보는 중입니다." + "value": "명" } ], "message.collected-data": [ @@ -1572,7 +1548,7 @@ "message.error": [ { "type": 0, - "value": "오류가 발생하였습니다." + "value": "오류가 발생했습니다." } ], "message.event-log": [ @@ -1598,19 +1574,19 @@ "message.incorrect-username-password": [ { "type": 0, - "value": "사용자 이름/비밀번호가 잘못되었습니다." + "value": "사용자 이름 또는 비밀번호를 잘못 입력했습니다." } ], "message.invalid-domain": [ { "type": 0, - "value": "잘못된 도메인" + "value": "잘못된 도메인입니다. http/https를 포함하지 마세요." } ], "message.min-password-length": [ { "type": 0, - "value": "최소 길이는 " + "value": "최소 " }, { "type": 1, @@ -1618,35 +1594,39 @@ }, { "type": 0, - "value": "자입니다" + "value": "자여야 합니다" } ], "message.new-version-available": [ { "type": 0, - "value": "새 버전이 사용 가능합니다! - Umami " + "value": "Umami의 새 버전 " }, { "type": 1, "value": "version" + }, + { + "type": 0, + "value": "을(를) 사용할 수 있습니다!" } ], "message.no-data-available": [ { "type": 0, - "value": "사용 가능한 데이터가 없습니다." + "value": "사용할 수 있는 데이터가 없습니다." } ], "message.no-event-data": [ { "type": 0, - "value": "사용 가능한 이벤트 데이터가 없습니다." + "value": "사용할 수 있는 이벤트 데이터가 없습니다." } ], "message.no-match-password": [ { "type": 0, - "value": "비밀번호가 일치하지 않음" + "value": "비밀번호가 일치하지 않습니다." } ], "message.no-results-found": [ @@ -1658,13 +1638,13 @@ "message.no-team-websites": [ { "type": 0, - "value": "이 팀에는 웹사이트가 없습니다." + "value": "팀에 웹사이트가 없습니다." } ], "message.no-teams": [ { "type": 0, - "value": "생성된 팀이 없습니다." + "value": "만든 팀이 없습니다." } ], "message.no-users": [ @@ -1682,13 +1662,13 @@ "message.page-not-found": [ { "type": 0, - "value": "페이지를 찾을 수 없습니다." + "value": "페이지를 찾을 수 없음" } ], "message.reset-website": [ { "type": 0, - "value": "이 웹사이트를 초기화하려면, 아래 상자에 " + "value": "이 웹사이트를 초기화하려면 아래 상자에 " }, { "type": 1, @@ -1696,7 +1676,7 @@ }, { "type": 0, - "value": "을(를) 입력하십시오." + "value": "을(를) 입력하세요." } ], "message.reset-website-warning": [ @@ -1708,7 +1688,7 @@ "message.saved": [ { "type": 0, - "value": "성공적으로 저장되었습니다." + "value": "저장했습니다." } ], "message.share-url": [ @@ -1720,7 +1700,7 @@ "message.team-already-member": [ { "type": 0, - "value": "이미 팀의 회원입니다." + "value": "이미 팀 멤버입니다." } ], "message.team-not-found": [ @@ -1732,13 +1712,13 @@ "message.team-websites-info": [ { "type": 0, - "value": "웹사이트는 팀의 누구나 볼 수 있습니다." + "value": "웹사이트는 팀 멤버 누구나 볼 수 있습니다." } ], "message.tracking-code": [ { "type": 0, - "value": "이 웹사이트의 통계를 추적하려면, 다음 코드를 HTML의 " + "value": "이 웹사이트의 통계를 추적하려면 다음 코드를 HTML의 " }, { "children": [ @@ -1752,7 +1732,7 @@ }, { "type": 0, - "value": " 섹션에 추가하십시오." + "value": " 부분에 추가하세요." } ], "message.transfer-team-website-to-user": [ @@ -1764,7 +1744,7 @@ "message.transfer-user-website-to-team": [ { "type": 0, - "value": "이 웹사이트를 전송받을 팀을 선택하십시오." + "value": "이 웹사이트를 전송받을 팀을 선택하세요." } ], "message.transfer-website": [ @@ -1782,53 +1762,53 @@ "message.user-deleted": [ { "type": 0, - "value": "사용자가 삭제되었습니다." + "value": "사용자를 삭제했습니다." } ], "message.viewed-page": [ { "type": 0, - "value": "페이지 조회" + "value": "조회한 페이지" } ], "message.visitor-log": [ { "type": 1, - "value": "country" + "value": "os" }, { "type": 0, - "value": "의 " + "value": " " }, { "type": 1, - "value": "browser" + "value": "device" }, { "type": 0, - "value": " 브라우저를 사용하는 " + "value": "에서 " }, { "type": 1, - "value": "os" + "value": "browser" }, { "type": 0, - "value": " " + "value": "을(를) 사용하는 " }, { "type": 1, - "value": "device" + "value": "country" }, { "type": 0, - "value": " 방문자" + "value": "의 방문자" } ], "message.visitors-dropped-off": [ { "type": 0, - "value": "방문자가 이탈했습니다" + "value": "방문자 이탈함" } ] } diff --git a/src/app/(main)/reports/retention/RetentionTable.tsx b/src/app/(main)/reports/retention/RetentionTable.tsx index 1770a76468..6d825567d4 100644 --- a/src/app/(main)/reports/retention/RetentionTable.tsx +++ b/src/app/(main)/reports/retention/RetentionTable.tsx @@ -58,13 +58,13 @@ export function RetentionTable({ days = DAYS }) { if (totalDays - rowIndex < day) { return null; } - const percentage = records[day]?.percentage; + const percentage = records.filter(a => a.day === day)[0]?.percentage; return (
- {percentage ? `${percentage.toFixed(2)}%` : ''} + {percentage ? `${Number(percentage).toFixed(2)}%` : ''}
); })} diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx index b4a02db799..398fbf8fde 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChartList.tsx @@ -47,7 +47,7 @@ export default function WebsiteChartList({ - + {showCharts && } ) : null; diff --git a/src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx b/src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx index 49b31656d3..32eb985c61 100644 --- a/src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx +++ b/src/app/(main)/websites/[websiteId]/events/EventsDataTable.tsx @@ -13,7 +13,7 @@ export default function EventsDataTable({ const queryResult = useWebsiteEvents(websiteId); return ( - + {({ data }) => } ); diff --git a/src/components/charts/BarChart.tsx b/src/components/charts/BarChart.tsx index b96812210e..7624ba1c43 100644 --- a/src/components/charts/BarChart.tsx +++ b/src/components/charts/BarChart.tsx @@ -1,9 +1,8 @@ -import { useMemo } from 'react'; -import { useTheme } from 'components/hooks'; +import BarChartTooltip from 'components/charts/BarChartTooltip'; import Chart, { ChartProps } from 'components/charts/Chart'; +import { useTheme } from 'components/hooks'; import { renderNumberLabels } from 'lib/charts'; -import { useState } from 'react'; -import BarChartTooltip from 'components/charts/BarChartTooltip'; +import { useMemo, useState } from 'react'; export interface BarChartProps extends ChartProps { unit: string; @@ -36,7 +35,7 @@ export function BarChart(props: BarChartProps) { x: { type: XAxisType, stacked: true, - min: minDate, + min: minDate && new Date(minDate).getSeconds() === 0 ? minDate : '', max: maxDate, time: { unit, diff --git a/src/components/common/DataTable.tsx b/src/components/common/DataTable.tsx index 22373f608e..d2094329b0 100644 --- a/src/components/common/DataTable.tsx +++ b/src/components/common/DataTable.tsx @@ -15,6 +15,7 @@ export interface DataTableProps { searchDelay?: number; allowSearch?: boolean; allowPaging?: boolean; + autoFocus?: boolean; renderEmpty?: () => ReactNode; children: ReactNode | ((data: any) => ReactNode); } @@ -24,6 +25,7 @@ export function DataTable({ searchDelay = 600, allowSearch = true, allowPaging = true, + autoFocus = true, renderEmpty, children, }: DataTableProps) { @@ -57,7 +59,7 @@ export function DataTable({ value={query} onSearch={handleSearch} delay={searchDelay || DEFAULT_SEARCH_DELAY} - autoFocus={true} + autoFocus={autoFocus} placeholder={formatMessage(labels.search)} /> )} diff --git a/src/components/metrics/EventsChart.tsx b/src/components/metrics/EventsChart.tsx index ee7f866cb3..f5b283449b 100644 --- a/src/components/metrics/EventsChart.tsx +++ b/src/components/metrics/EventsChart.tsx @@ -47,6 +47,8 @@ export function EventsChart({ websiteId, className }: EventsChartProps) { return ( ... 섹션에 추가하십시오.", + "message.team-websites-info": "웹사이트는 팀 멤버 누구나 볼 수 있습니다.", + "message.tracking-code": "이 웹사이트의 통계를 추적하려면 다음 코드를 HTML의 ... 부분에 추가하세요.", "message.transfer-team-website-to-user": "이 웹사이트를 당신의 계정으로 전송하시겠습니까?", - "message.transfer-user-website-to-team": "이 웹사이트를 전송받을 팀을 선택하십시오.", + "message.transfer-user-website-to-team": "이 웹사이트를 전송받을 팀을 선택하세요.", "message.transfer-website": "웹사이트 소유권을 계정이나 다른 팀으로 전송합니다.", "message.triggered-event": "트리거된 이벤트", - "message.user-deleted": "사용자가 삭제되었습니다.", - "message.viewed-page": "페이지 조회", - "message.visitor-log": "{country}의 {browser} 브라우저를 사용하는 {os} {device} 방문자", - "message.visitors-dropped-off": "방문자가 이탈했습니다" + "message.user-deleted": "사용자를 삭제했습니다.", + "message.viewed-page": "조회한 페이지", + "message.visitor-log": "{os} {device}에서 {browser}을(를) 사용하는 {country}의 방문자", + "message.visitors-dropped-off": "방문자 이탈함" } diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index 332d07275c..5502b5babf 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -63,9 +63,9 @@ function getDateStringSQL(data: any, unit: string = 'utc', timezone?: string) { function getDateSQL(field: string, unit: string, timezone?: string) { if (timezone) { - return `date_trunc('${unit}', ${field}, '${timezone}')`; + return `toDateTime(date_trunc('${unit}', ${field}, '${timezone}'), '${timezone}')`; } - return `date_trunc('${unit}', ${field})`; + return `toDateTime(date_trunc('${unit}', ${field}))`; } function mapFilter(column: string, operator: string, name: string, type: string = 'String') { diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index f0f071bc79..32ac65eb5f 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -14,17 +14,17 @@ const log = debug('umami:prisma'); const MYSQL_DATE_FORMATS = { minute: '%Y-%m-%dT%H:%i:00', hour: '%Y-%m-%d %H:00:00', - day: '%Y-%m-%d', - month: '%Y-%m-01', - year: '%Y-01-01', + day: '%Y-%m-%d 00:00:00', + month: '%Y-%m-01 00:00:00', + year: '%Y-01-01 00:00:00', }; const POSTGRESQL_DATE_FORMATS = { minute: 'YYYY-MM-DD HH24:MI:00', hour: 'YYYY-MM-DD HH24:00:00', - day: 'YYYY-MM-DD', - month: 'YYYY-MM-01', - year: 'YYYY-01-01', + day: 'YYYY-MM-DD HH24:00:00', + month: 'YYYY-MM-01 HH24:00:00', + year: 'YYYY-01-01 HH24:00:00', }; function getAddIntervalQuery(field: string, interval: string): string { diff --git a/src/queries/analytics/pageviews/getPageviewStats.ts b/src/queries/analytics/pageviews/getPageviewStats.ts index 96e9f1e131..48b82000aa 100644 --- a/src/queries/analytics/pageviews/getPageviewStats.ts +++ b/src/queries/analytics/pageviews/getPageviewStats.ts @@ -41,8 +41,8 @@ async function clickhouseQuery( websiteId: string, filters: QueryFilters, ): Promise<{ x: string; y: number }[]> { - const { unit = 'day' } = filters; - const { parseFilters, rawQuery } = clickhouse; + const { timezone = 'utc', unit = 'day' } = filters; + const { parseFilters, rawQuery, getDateSQL } = clickhouse; const { filterQuery, params } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, @@ -57,7 +57,7 @@ async function clickhouseQuery( g.y as y from ( select - date_trunc('${unit}', created_at) as t, + ${getDateSQL('website_event.created_at', unit, timezone)} as t, count(*) as y from website_event where website_id = {websiteId:UUID} @@ -75,7 +75,7 @@ async function clickhouseQuery( g.y as y from ( select - date_trunc('${unit}', created_at) as t, + ${getDateSQL('website_event.created_at', unit, timezone)} as t, sum(views)as y from website_event_stats_hourly website_event where website_id = {websiteId:UUID} diff --git a/src/queries/analytics/reports/getRetention.ts b/src/queries/analytics/reports/getRetention.ts index eb184e1806..d69a77d7bf 100644 --- a/src/queries/analytics/reports/getRetention.ts +++ b/src/queries/analytics/reports/getRetention.ts @@ -110,7 +110,7 @@ async function clickhouseQuery( }[] > { const { startDate, endDate, timezone = 'UTC' } = filters; - const { getDateSQL, getDateStringSQL, rawQuery } = clickhouse; + const { getDateSQL, rawQuery } = clickhouse; const unit = 'day'; return rawQuery( @@ -152,7 +152,7 @@ async function clickhouseQuery( group by 1, 2 ) select - ${getDateStringSQL('c.cohort_date', unit)} as date, + c.cohort_date as date, c.day_number as day, s.visitors as visitors, c.visitors returnVisitors, diff --git a/src/queries/analytics/sessions/getSessionStats.ts b/src/queries/analytics/sessions/getSessionStats.ts index 8fde94f379..212f15e9bd 100644 --- a/src/queries/analytics/sessions/getSessionStats.ts +++ b/src/queries/analytics/sessions/getSessionStats.ts @@ -41,8 +41,8 @@ async function clickhouseQuery( websiteId: string, filters: QueryFilters, ): Promise<{ x: string; y: number }[]> { - const { unit = 'day' } = filters; - const { parseFilters, rawQuery } = clickhouse; + const { timezone = 'utc', unit = 'day' } = filters; + const { parseFilters, rawQuery, getDateSQL } = clickhouse; const { filterQuery, params } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, @@ -53,11 +53,11 @@ async function clickhouseQuery( if (EVENT_COLUMNS.some(item => Object.keys(filters).includes(item)) || unit === 'minute') { sql = ` select - g.t as x, + g.t as x, g.y as y from ( select - date_trunc('${unit}', created_at) as t, + ${getDateSQL('website_event.created_at', unit, timezone)} as t, count(distinct session_id) as y from website_event where website_id = {websiteId:UUID} @@ -71,11 +71,11 @@ async function clickhouseQuery( } else { sql = ` select - g.t as x, + g.t as x, g.y as y from ( select - date_trunc('${unit}', created_at) as t, + ${getDateSQL('website_event.created_at', unit, timezone)} as t, uniq(session_id) as y from website_event_stats_hourly website_event where website_id = {websiteId:UUID} diff --git a/src/tracker/index.js b/src/tracker/index.js index 90a73c432b..707594cf40 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -222,6 +222,16 @@ } }; + const init = () => { + if (!initialized) { + track(); + handlePathChanges(); + handleTitleChanges(); + handleClicks(); + initialized = true; + } + }; + const track = (obj, data) => { if (typeof obj === 'string') { return send({ @@ -255,19 +265,10 @@ let initialized; if (autoTrack && !trackingDisabled()) { - handlePathChanges(); - handleTitleChanges(); - handleClicks(); - - const init = () => { - if (document.readyState === 'complete' && !initialized) { - track(); - initialized = true; - } - }; - - document.addEventListener('readystatechange', init, true); - - init(); + if (document.readyState === 'complete') { + init(); + } else { + document.addEventListener('readystatechange', init, true); + } } })(window);