mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
commit
35068d34a6
@ -12,6 +12,7 @@ services:
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
init: true
|
||||
restart: always
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
|
||||
|
18
package.json
18
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "umami",
|
||||
"version": "2.14.0",
|
||||
"version": "2.15.0",
|
||||
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
|
||||
"author": "Umami Software, Inc. <hello@umami.is>",
|
||||
"license": "MIT",
|
||||
@ -63,18 +63,21 @@
|
||||
"cacheDirectories": [
|
||||
".next/cache"
|
||||
],
|
||||
"resolutions": {
|
||||
"jackspeak": "2.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@clickhouse/client": "^1.4.1",
|
||||
"@date-fns/utc": "^1.2.0",
|
||||
"@dicebear/collection": "^9.2.1",
|
||||
"@dicebear/core": "^9.2.1",
|
||||
"@fontsource/inter": "^4.5.15",
|
||||
"@prisma/client": "5.17",
|
||||
"@prisma/client": "5.22.0",
|
||||
"@prisma/extension-read-replicas": "^0.3.0",
|
||||
"@react-spring/web": "^9.7.3",
|
||||
"@tanstack/react-query": "^5.28.6",
|
||||
"@umami/prisma-client": "^0.14.0",
|
||||
"@umami/redis-client": "^0.21.0",
|
||||
"@umami/redis-client": "^0.24.0",
|
||||
"chalk": "^4.1.1",
|
||||
"chart.js": "^4.4.2",
|
||||
"chartjs-adapter-date-fns": "^3.0.0",
|
||||
@ -99,16 +102,15 @@
|
||||
"kafkajs": "^2.1.0",
|
||||
"maxmind": "^4.3.6",
|
||||
"md5": "^2.3.0",
|
||||
"moment-timezone": "^0.5.35",
|
||||
"next": "14.2.10",
|
||||
"next": "15.0.4",
|
||||
"next-basics": "^0.39.0",
|
||||
"node-fetch": "^3.2.8",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prisma": "5.17",
|
||||
"react": "^18.2.0",
|
||||
"prisma": "5.22.0",
|
||||
"react": "^19.0.0",
|
||||
"react-basics": "^0.125.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-error-boundary": "^4.0.4",
|
||||
"react-intl": "^6.5.5",
|
||||
"react-simple-maps": "^2.3.0",
|
||||
|
@ -1450,7 +1450,7 @@
|
||||
"label.visits": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "訪問者数"
|
||||
"value": "訪問数"
|
||||
}
|
||||
],
|
||||
"label.website": [
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -476,7 +476,7 @@
|
||||
"label.first-seen": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "First seen"
|
||||
"value": "首次出现"
|
||||
}
|
||||
],
|
||||
"label.funnel": [
|
||||
@ -656,7 +656,7 @@
|
||||
"label.last-seen": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Last seen"
|
||||
"value": "最后出现"
|
||||
}
|
||||
],
|
||||
"label.leave": [
|
||||
@ -1050,19 +1050,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": [
|
||||
@ -1296,7 +1296,7 @@
|
||||
"label.transactions": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Transactions"
|
||||
"value": "交易"
|
||||
}
|
||||
],
|
||||
"label.transfer": [
|
||||
@ -1338,7 +1338,7 @@
|
||||
"label.uniqueCustomers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Unique Customers"
|
||||
"value": "独特客户"
|
||||
}
|
||||
],
|
||||
"label.unknown": [
|
||||
@ -1380,7 +1380,7 @@
|
||||
"label.user-property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "User Property"
|
||||
"value": "用户属性"
|
||||
}
|
||||
],
|
||||
"label.username": [
|
||||
|
@ -8,13 +8,13 @@
|
||||
"label.actions": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "行動"
|
||||
"value": "行為"
|
||||
}
|
||||
],
|
||||
"label.activity": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "活動日誌"
|
||||
"value": "活動紀錄"
|
||||
}
|
||||
],
|
||||
"label.add": [
|
||||
@ -32,13 +32,13 @@
|
||||
"label.add-member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Add member"
|
||||
"value": "新增成員"
|
||||
}
|
||||
],
|
||||
"label.add-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Add step"
|
||||
"value": "新增步驟"
|
||||
}
|
||||
],
|
||||
"label.add-website": [
|
||||
@ -104,7 +104,7 @@
|
||||
"label.breakdown": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "分解"
|
||||
"value": "細項分析"
|
||||
}
|
||||
],
|
||||
"label.browser": [
|
||||
@ -152,7 +152,7 @@
|
||||
"label.compare": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Compare"
|
||||
"value": "比較"
|
||||
}
|
||||
],
|
||||
"label.confirm": [
|
||||
@ -182,7 +182,7 @@
|
||||
"label.count": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Count"
|
||||
"value": "數量"
|
||||
}
|
||||
],
|
||||
"label.countries": [
|
||||
@ -206,7 +206,7 @@
|
||||
"label.create-report": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "建立報告"
|
||||
"value": "建立報表"
|
||||
}
|
||||
],
|
||||
"label.create-team": [
|
||||
@ -230,13 +230,13 @@
|
||||
"label.created-by": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Created By"
|
||||
"value": "建立者"
|
||||
}
|
||||
],
|
||||
"label.current": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Current"
|
||||
"value": "目前"
|
||||
}
|
||||
],
|
||||
"label.current-password": [
|
||||
@ -296,7 +296,7 @@
|
||||
"label.delete-report": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Delete report"
|
||||
"value": "刪除報表"
|
||||
}
|
||||
],
|
||||
"label.delete-team": [
|
||||
@ -368,7 +368,7 @@
|
||||
"label.dropoff": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "退出"
|
||||
"value": "離開"
|
||||
}
|
||||
],
|
||||
"label.edit": [
|
||||
@ -386,25 +386,25 @@
|
||||
"label.edit-member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Edit member"
|
||||
"value": "編輯成員"
|
||||
}
|
||||
],
|
||||
"label.enable-share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "啟用分享網址"
|
||||
"value": "啟用分享連結"
|
||||
}
|
||||
],
|
||||
"label.end-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "End Step"
|
||||
"value": "結束步驟"
|
||||
}
|
||||
],
|
||||
"label.entry": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Entry URL"
|
||||
"value": "進入網址"
|
||||
}
|
||||
],
|
||||
"label.event": [
|
||||
@ -428,7 +428,7 @@
|
||||
"label.exit": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Exit URL"
|
||||
"value": "離開網址"
|
||||
}
|
||||
],
|
||||
"label.false": [
|
||||
@ -470,43 +470,43 @@
|
||||
"label.filters": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "篩選器"
|
||||
"value": "篩選條件"
|
||||
}
|
||||
],
|
||||
"label.first-seen": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "First seen"
|
||||
"value": "首次造訪"
|
||||
}
|
||||
],
|
||||
"label.funnel": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "漏斗"
|
||||
"value": "漏斗分析"
|
||||
}
|
||||
],
|
||||
"label.funnel-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "瞭解使用者的轉換率和退出率"
|
||||
"value": "瞭解使用者的轉換率與流失率。"
|
||||
}
|
||||
],
|
||||
"label.goal": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Goal"
|
||||
"value": "目標"
|
||||
}
|
||||
],
|
||||
"label.goals": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Goals"
|
||||
"value": "目標"
|
||||
}
|
||||
],
|
||||
"label.goals-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Track your goals for pageviews and events."
|
||||
"value": "追蹤網頁瀏覽和事件的目標。"
|
||||
}
|
||||
],
|
||||
"label.greater-than": [
|
||||
@ -524,13 +524,13 @@
|
||||
"label.host": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Host"
|
||||
"value": "主機名稱"
|
||||
}
|
||||
],
|
||||
"label.hosts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Hosts"
|
||||
"value": "主機名稱"
|
||||
}
|
||||
],
|
||||
"label.insights": [
|
||||
@ -542,7 +542,7 @@
|
||||
"label.insights-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "透過使用區段和篩選器來深入探索你的數據"
|
||||
"value": "使用區段和篩選器來深入分析您的資料。"
|
||||
}
|
||||
],
|
||||
"label.is": [
|
||||
@ -584,13 +584,13 @@
|
||||
"label.journey": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Journey"
|
||||
"value": "使用者旅程"
|
||||
}
|
||||
],
|
||||
"label.journey-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Understand how users navigate through your website."
|
||||
"value": "瞭解使用者如何瀏覽您的網站。"
|
||||
}
|
||||
],
|
||||
"label.language": [
|
||||
@ -642,7 +642,7 @@
|
||||
"label.last-months": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Last "
|
||||
"value": "最近 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -650,13 +650,13 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " months"
|
||||
"value": " 個月"
|
||||
}
|
||||
],
|
||||
"label.last-seen": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Last seen"
|
||||
"value": "最後造訪"
|
||||
}
|
||||
],
|
||||
"label.leave": [
|
||||
@ -698,25 +698,25 @@
|
||||
"label.manage": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Manage"
|
||||
"value": "管理"
|
||||
}
|
||||
],
|
||||
"label.manager": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Manager"
|
||||
"value": "管理者"
|
||||
}
|
||||
],
|
||||
"label.max": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "最大"
|
||||
"value": "最大值"
|
||||
}
|
||||
],
|
||||
"label.member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Member"
|
||||
"value": "成員"
|
||||
}
|
||||
],
|
||||
"label.members": [
|
||||
@ -728,7 +728,7 @@
|
||||
"label.min": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "最小"
|
||||
"value": "最小值"
|
||||
}
|
||||
],
|
||||
"label.mobile": [
|
||||
@ -746,7 +746,7 @@
|
||||
"label.my-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "My account"
|
||||
"value": "我的帳號"
|
||||
}
|
||||
],
|
||||
"label.my-websites": [
|
||||
@ -780,31 +780,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " "
|
||||
},
|
||||
{
|
||||
"offset": 0,
|
||||
"options": {
|
||||
"one": {
|
||||
"value": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "record"
|
||||
}
|
||||
]
|
||||
},
|
||||
"other": {
|
||||
"value": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "records"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"pluralType": "cardinal",
|
||||
"type": 6,
|
||||
"value": "x"
|
||||
"value": " 筆紀錄"
|
||||
}
|
||||
],
|
||||
"label.ok": [
|
||||
@ -822,7 +798,7 @@
|
||||
"label.overview": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "概覽"
|
||||
"value": "總覽"
|
||||
}
|
||||
],
|
||||
"label.owner": [
|
||||
@ -834,7 +810,7 @@
|
||||
"label.page-of": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "頁面 "
|
||||
"value": "第 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -842,29 +818,33 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " / "
|
||||
"value": " 頁,共 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "total"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " 頁"
|
||||
}
|
||||
],
|
||||
"label.page-views": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "頁面瀏覽"
|
||||
"value": "網頁瀏覽次數"
|
||||
}
|
||||
],
|
||||
"label.pageTitle": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "頁面標題"
|
||||
"value": "網頁標題"
|
||||
}
|
||||
],
|
||||
"label.pages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "頁面"
|
||||
"value": "網頁"
|
||||
}
|
||||
],
|
||||
"label.password": [
|
||||
@ -876,13 +856,13 @@
|
||||
"label.path": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Path"
|
||||
"value": "路徑"
|
||||
}
|
||||
],
|
||||
"label.paths": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Paths"
|
||||
"value": "路徑"
|
||||
}
|
||||
],
|
||||
"label.powered-by": [
|
||||
@ -896,43 +876,43 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " 提供"
|
||||
"value": " 提供技術支援"
|
||||
}
|
||||
],
|
||||
"label.previous": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous"
|
||||
"value": "上一個"
|
||||
}
|
||||
],
|
||||
"label.previous-period": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous period"
|
||||
"value": "上一期間"
|
||||
}
|
||||
],
|
||||
"label.previous-year": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous year"
|
||||
"value": "去年"
|
||||
}
|
||||
],
|
||||
"label.profile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "個人資料"
|
||||
"value": "個人檔案"
|
||||
}
|
||||
],
|
||||
"label.properties": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Properties"
|
||||
"value": "屬性"
|
||||
}
|
||||
],
|
||||
"label.property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Property"
|
||||
"value": "屬性"
|
||||
}
|
||||
],
|
||||
"label.queries": [
|
||||
@ -986,13 +966,13 @@
|
||||
"label.region": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "區域"
|
||||
"value": "地區"
|
||||
}
|
||||
],
|
||||
"label.regions": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "區域"
|
||||
"value": "地區"
|
||||
}
|
||||
],
|
||||
"label.remove": [
|
||||
@ -1004,13 +984,13 @@
|
||||
"label.remove-member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Remove member"
|
||||
"value": "移除成員"
|
||||
}
|
||||
],
|
||||
"label.reports": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "報告"
|
||||
"value": "報表"
|
||||
}
|
||||
],
|
||||
"label.required": [
|
||||
@ -1028,13 +1008,13 @@
|
||||
"label.reset-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "重設網站"
|
||||
"value": "重設網站統計資料"
|
||||
}
|
||||
],
|
||||
"label.retention": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "保留"
|
||||
"value": "留存率"
|
||||
}
|
||||
],
|
||||
"label.retention-description": [
|
||||
@ -1046,19 +1026,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": [
|
||||
@ -1088,37 +1068,37 @@
|
||||
"label.search": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Search"
|
||||
"value": "搜尋"
|
||||
}
|
||||
],
|
||||
"label.select": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Select"
|
||||
"value": "選取"
|
||||
}
|
||||
],
|
||||
"label.select-date": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "選擇日期"
|
||||
"value": "選取日期"
|
||||
}
|
||||
],
|
||||
"label.select-role": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Select role"
|
||||
"value": "選取角色"
|
||||
}
|
||||
],
|
||||
"label.select-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "選擇網站"
|
||||
"value": "選取網站"
|
||||
}
|
||||
],
|
||||
"label.session": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Session"
|
||||
"value": "工作階段"
|
||||
}
|
||||
],
|
||||
"label.sessions": [
|
||||
@ -1136,7 +1116,7 @@
|
||||
"label.share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "分享網址"
|
||||
"value": "分享連結"
|
||||
}
|
||||
],
|
||||
"label.single-day": [
|
||||
@ -1148,13 +1128,13 @@
|
||||
"label.start-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Start Step"
|
||||
"value": "起始步驟"
|
||||
}
|
||||
],
|
||||
"label.steps": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Steps"
|
||||
"value": "步驟"
|
||||
}
|
||||
],
|
||||
"label.sum": [
|
||||
@ -1184,7 +1164,7 @@
|
||||
"label.team-manager": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Team manager"
|
||||
"value": "團隊管理者"
|
||||
}
|
||||
],
|
||||
"label.team-member": [
|
||||
@ -1208,7 +1188,7 @@
|
||||
"label.team-view-only": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Team view only"
|
||||
"value": "團隊僅供檢視"
|
||||
}
|
||||
],
|
||||
"label.team-websites": [
|
||||
@ -1280,7 +1260,7 @@
|
||||
"label.total-records": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "總記錄"
|
||||
"value": "紀錄總數"
|
||||
}
|
||||
],
|
||||
"label.tracking-code": [
|
||||
@ -1292,19 +1272,19 @@
|
||||
"label.transactions": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Transactions"
|
||||
"value": "交易"
|
||||
}
|
||||
],
|
||||
"label.transfer": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Transfer"
|
||||
"value": "轉移"
|
||||
}
|
||||
],
|
||||
"label.transfer-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Transfer website"
|
||||
"value": "轉移網站"
|
||||
}
|
||||
],
|
||||
"label.true": [
|
||||
@ -1322,19 +1302,19 @@
|
||||
"label.unique": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "獨立"
|
||||
"value": "不重複"
|
||||
}
|
||||
],
|
||||
"label.unique-visitors": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "獨立訪客"
|
||||
"value": "不重複訪客"
|
||||
}
|
||||
],
|
||||
"label.uniqueCustomers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Unique Customers"
|
||||
"value": "不重複客戶"
|
||||
}
|
||||
],
|
||||
"label.unknown": [
|
||||
@ -1346,13 +1326,13 @@
|
||||
"label.untitled": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "無標題"
|
||||
"value": "未命名"
|
||||
}
|
||||
],
|
||||
"label.update": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Update"
|
||||
"value": "更新"
|
||||
}
|
||||
],
|
||||
"label.url": [
|
||||
@ -1376,7 +1356,7 @@
|
||||
"label.user-property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "User Property"
|
||||
"value": "使用者屬性"
|
||||
}
|
||||
],
|
||||
"label.username": [
|
||||
@ -1400,7 +1380,7 @@
|
||||
"label.utm-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Track your campaigns through UTM parameters."
|
||||
"value": "透過 UTM 參數追蹤您的行銷活動。"
|
||||
}
|
||||
],
|
||||
"label.value": [
|
||||
@ -1430,19 +1410,19 @@
|
||||
"label.views": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "檢視"
|
||||
"value": "瀏覽次數"
|
||||
}
|
||||
],
|
||||
"label.views-per-visit": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Views per visit"
|
||||
"value": "每次造訪的瀏覽次數"
|
||||
}
|
||||
],
|
||||
"label.visit-duration": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "平均造訪時間"
|
||||
"value": "造訪時間"
|
||||
}
|
||||
],
|
||||
"label.visitors": [
|
||||
@ -1454,7 +1434,7 @@
|
||||
"label.visits": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visits"
|
||||
"value": "造訪次數"
|
||||
}
|
||||
],
|
||||
"label.website": [
|
||||
@ -1490,7 +1470,7 @@
|
||||
"message.action-confirmation": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Type "
|
||||
"value": "請在下方欄位輸入 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -1498,7 +1478,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " in the box below to confirm."
|
||||
"value": " 以確認。"
|
||||
}
|
||||
],
|
||||
"message.active-users": [
|
||||
@ -1512,13 +1492,13 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " 個活躍的訪客"
|
||||
"value": " 位訪客"
|
||||
}
|
||||
],
|
||||
"message.collected-data": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Collected data"
|
||||
"value": "已蒐集的資料"
|
||||
}
|
||||
],
|
||||
"message.confirm-delete": [
|
||||
@ -1552,7 +1532,7 @@
|
||||
"message.confirm-remove": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Are you sure you want to remove "
|
||||
"value": "您確定要移除 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -1560,7 +1540,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": "?"
|
||||
"value": " 嗎?"
|
||||
}
|
||||
],
|
||||
"message.confirm-reset": [
|
||||
@ -1574,19 +1554,19 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " 嗎?"
|
||||
"value": " 的統計資料嗎?"
|
||||
}
|
||||
],
|
||||
"message.delete-team-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Deleting a team will also delete all team websites."
|
||||
"value": "刪除團隊的同時也會刪除所有團隊的網站。"
|
||||
}
|
||||
],
|
||||
"message.delete-website-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "所有網站資料將被刪除。"
|
||||
"value": "所有網站資料都將被刪除。"
|
||||
}
|
||||
],
|
||||
"message.error": [
|
||||
@ -1596,17 +1576,21 @@
|
||||
}
|
||||
],
|
||||
"message.event-log": [
|
||||
{
|
||||
"type": 1,
|
||||
"value": "event"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " 在 "
|
||||
"value": "在 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "url"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " 上的 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "event"
|
||||
}
|
||||
],
|
||||
"message.go-to-settings": [
|
||||
@ -1618,19 +1602,19 @@
|
||||
"message.incorrect-username-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "使用者名稱和/或密碼不正確。"
|
||||
"value": "使用者名稱或密碼不正確。"
|
||||
}
|
||||
],
|
||||
"message.invalid-domain": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "無效的網域。請不要包含 http/https。"
|
||||
"value": "無效的網域。請勿包含 http/https。"
|
||||
}
|
||||
],
|
||||
"message.min-password-length": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "最少需要 "
|
||||
"value": "密碼長度至少需 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -1652,7 +1636,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " 的新版本已經可以使用!"
|
||||
"value": " 的新版本已推出!"
|
||||
}
|
||||
],
|
||||
"message.no-data-available": [
|
||||
@ -1694,7 +1678,7 @@
|
||||
"message.no-users": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "沒有使用者。"
|
||||
"value": "沒有任何使用者。"
|
||||
}
|
||||
],
|
||||
"message.no-websites-configured": [
|
||||
@ -1706,13 +1690,13 @@
|
||||
"message.page-not-found": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "找不到頁面"
|
||||
"value": "找不到網頁"
|
||||
}
|
||||
],
|
||||
"message.reset-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "要重設此網站,請在下方的方框中輸入 "
|
||||
"value": "要重設此網站的統計資料,請在下方欄位輸入 "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -1726,7 +1710,7 @@
|
||||
"message.reset-website-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "此網站的所有統計將被刪除,但您的設定將保持不變。"
|
||||
"value": "此網站的所有統計資料都將被刪除,但您的設定將保持不變。"
|
||||
}
|
||||
],
|
||||
"message.saved": [
|
||||
@ -1738,13 +1722,13 @@
|
||||
"message.share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "您的網站統計資料可以在以下網址公開檢視:"
|
||||
"value": "您的網站統計資料可在以下網址公開檢視:"
|
||||
}
|
||||
],
|
||||
"message.team-already-member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "您已經是團隊的成員。"
|
||||
"value": "您已是該團隊的成員。"
|
||||
}
|
||||
],
|
||||
"message.team-not-found": [
|
||||
@ -1756,13 +1740,13 @@
|
||||
"message.team-websites-info": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "團隊的任何成員都可以檢視網站。"
|
||||
"value": "團隊中的所有成員都可以檢視網站。"
|
||||
}
|
||||
],
|
||||
"message.tracking-code": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "要追蹤此網站的統計,請將以下代碼放在您的 HTML 的 "
|
||||
"value": "要追蹤此網站的統計資料,請將以下程式碼放在您 HTML 的 "
|
||||
},
|
||||
{
|
||||
"children": [
|
||||
@ -1782,25 +1766,25 @@
|
||||
"message.transfer-team-website-to-user": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Transfer this website to your account?"
|
||||
"value": "要將此網站轉移至您的帳號嗎?"
|
||||
}
|
||||
],
|
||||
"message.transfer-user-website-to-team": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Select the team to transfer this website to."
|
||||
"value": "請選擇要轉移此網站的團隊。"
|
||||
}
|
||||
],
|
||||
"message.transfer-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Transfer website ownership to your account or another team."
|
||||
"value": "將網站所有權轉移至您的帳號或其他團隊。"
|
||||
}
|
||||
],
|
||||
"message.triggered-event": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Triggered event"
|
||||
"value": "已觸發的事件"
|
||||
}
|
||||
],
|
||||
"message.user-deleted": [
|
||||
@ -1812,7 +1796,7 @@
|
||||
"message.viewed-page": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Viewed page"
|
||||
"value": "已瀏覽的網頁"
|
||||
}
|
||||
],
|
||||
"message.visitor-log": [
|
||||
@ -1856,7 +1840,7 @@
|
||||
"message.visitors-dropped-off": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visitors dropped off"
|
||||
"value": "訪客已離開"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -86,12 +86,10 @@ export function NavBar() {
|
||||
if (!cloudMode) {
|
||||
const teamIdLocal = getItem('umami.team')?.id;
|
||||
|
||||
if (teamIdLocal && pathname !== '/' && pathname !== '/dashboard') {
|
||||
const url = '/';
|
||||
router.push(url);
|
||||
} else if (teamIdLocal) {
|
||||
const url = `/teams/${teamIdLocal}/dashboard`;
|
||||
router.push(url);
|
||||
if (teamIdLocal && teamIdLocal !== teamId) {
|
||||
router.push(
|
||||
pathname !== '/' && pathname !== '/dashboard' ? '/' : `/teams/${teamIdLocal}/dashboard`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}, [cloudMode]);
|
||||
|
@ -5,7 +5,9 @@ async function getEnabled() {
|
||||
return !!process.env.ENABLE_TEST_CONSOLE;
|
||||
}
|
||||
|
||||
export default async function ({ params: { websiteId } }) {
|
||||
export default async function ({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
const enabled = await getEnabled();
|
||||
|
||||
if (!enabled) {
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import { Dropdown, Item, Button, Flexbox } from 'react-basics';
|
||||
import moment from 'moment-timezone';
|
||||
import { useTimezone, useMessages } from 'components/hooks';
|
||||
import { getTimezone } from 'lib/date';
|
||||
import styles from './TimezoneSetting.module.css';
|
||||
|
||||
const timezones = moment.tz.names();
|
||||
const timezones = Intl.supportedValuesOf('timeZone');
|
||||
|
||||
export function TimezoneSetting() {
|
||||
const [search, setSearch] = useState('');
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Metadata } from 'next';
|
||||
import ReportPage from './ReportPage';
|
||||
|
||||
export default function ({ params: { reportId } }) {
|
||||
export default async function ({ params }: { params: { reportId: string } }) {
|
||||
const { reportId } = await params;
|
||||
|
||||
return <ReportPage reportId={reportId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import UserPage from './UserPage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function ({ params: { userId } }) {
|
||||
export default async function ({ params }: { params: { userId: string } }) {
|
||||
const { userId } = await params;
|
||||
|
||||
return <UserPage userId={userId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import WebsiteSettingsPage from './WebsiteSettingsPage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default async function ({ params: { websiteId } }) {
|
||||
export default async function ({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <WebsiteSettingsPage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Metadata } from 'next';
|
||||
import WebsitesSettingsPage from './WebsitesSettingsPage';
|
||||
|
||||
export default function ({ params: { teamId } }: { params: { teamId: string } }) {
|
||||
export default async function ({ params }: { params: { teamId: string } }) {
|
||||
const { teamId } = await params;
|
||||
|
||||
return <WebsitesSettingsPage teamId={teamId} />;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,15 @@ import TeamProvider from './TeamProvider';
|
||||
import { Metadata } from 'next';
|
||||
import TeamSettingsLayout from './settings/TeamSettingsLayout';
|
||||
|
||||
export default function ({ children, params: { teamId } }) {
|
||||
export default async function ({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: any;
|
||||
params: { teamId: string };
|
||||
}) {
|
||||
const { teamId } = await params;
|
||||
|
||||
return (
|
||||
<TeamProvider teamId={teamId}>
|
||||
<TeamSettingsLayout>{children}</TeamSettingsLayout>
|
||||
|
@ -1,7 +1,9 @@
|
||||
import TeamMembersPage from './TeamMembersPage';
|
||||
import { Metadata } from 'next';
|
||||
import TeamMembersPage from './TeamMembersPage';
|
||||
|
||||
export default async function ({ params }: { params: { teamId: string } }) {
|
||||
const { teamId } = await params;
|
||||
|
||||
export default function ({ params: { teamId } }) {
|
||||
return <TeamMembersPage teamId={teamId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Metadata } from 'next';
|
||||
import TeamPage from './TeamPage';
|
||||
|
||||
export default function ({ params: { teamId } }) {
|
||||
export default async function ({ params }: { params: { teamId: string } }) {
|
||||
const { teamId } = await params;
|
||||
|
||||
return <TeamPage teamId={teamId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import TeamWebsitesPage from './TeamWebsitesPage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function ({ params: { teamId } }) {
|
||||
export default async function ({ params }: { params: { teamId: string } }) {
|
||||
const { teamId } = await params;
|
||||
|
||||
return <TeamWebsitesPage teamId={teamId} />;
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,7 @@ export function WebsiteChart({
|
||||
compareMode?: boolean;
|
||||
}) {
|
||||
const { dateRange, dateCompare } = useDateRange(websiteId);
|
||||
const { startDate, endDate, unit } = dateRange;
|
||||
const { startDate, endDate, unit, value } = dateRange;
|
||||
const { data, isLoading } = useWebsitePageviews(websiteId, compareMode ? dateCompare : undefined);
|
||||
const { pageviews, sessions, compare } = (data || {}) as any;
|
||||
|
||||
@ -49,6 +49,7 @@ export function WebsiteChart({
|
||||
maxDate={endDate.toISOString()}
|
||||
unit={unit}
|
||||
isLoading={isLoading}
|
||||
isAllTime={value === 'all'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
import WebsiteComparePage from './WebsiteComparePage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function ({ params: { websiteId } }) {
|
||||
export default async function ({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <WebsiteComparePage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import { Metadata } from 'next';
|
||||
import EventsPage from './EventsPage';
|
||||
|
||||
export default async function ({ params: { websiteId } }) {
|
||||
export default async function ({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <EventsPage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,15 @@
|
||||
import { Metadata } from 'next';
|
||||
import WebsiteProvider from './WebsiteProvider';
|
||||
|
||||
export default function ({ children, params: { websiteId } }) {
|
||||
export default async function ({
|
||||
children,
|
||||
params,
|
||||
}: {
|
||||
children: any;
|
||||
params: { websiteId: string };
|
||||
}) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <WebsiteProvider websiteId={websiteId}>{children}</WebsiteProvider>;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import WebsiteDetailsPage from './WebsiteDetailsPage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function WebsitePage({ params: { websiteId } }) {
|
||||
export default async function WebsitePage({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <WebsiteDetailsPage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import WebsiteRealtimePage from './WebsiteRealtimePage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function ({ params: { websiteId } }) {
|
||||
export default async function ({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <WebsiteRealtimePage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import WebsiteReportsPage from './WebsiteReportsPage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function ({ params: { websiteId } }) {
|
||||
export default async function ({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <WebsiteReportsPage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,8 @@
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
display: grid;
|
||||
grid-template-columns: max-content max-content 1fr;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
@ -15,10 +16,6 @@
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.value {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.header {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export function SessionActivity({
|
||||
</StatusLight>
|
||||
</div>
|
||||
<Icon>{eventName ? <Icons.Bolt /> : <Icons.Eye />}</Icon>
|
||||
<div className={styles.value}>{eventName || urlPath}</div>
|
||||
<div>{eventName || urlPath}</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -1,7 +1,13 @@
|
||||
import SessionDetailsPage from './SessionDetailsPage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function WebsitePage({ params: { websiteId, sessionId } }) {
|
||||
export default async function WebsitePage({
|
||||
params,
|
||||
}: {
|
||||
params: { websiteId: string; sessionId: string };
|
||||
}) {
|
||||
const { websiteId, sessionId } = await params;
|
||||
|
||||
return <SessionDetailsPage websiteId={websiteId} sessionId={sessionId} />;
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,9 @@
|
||||
import SessionsPage from './SessionsPage';
|
||||
import { Metadata } from 'next';
|
||||
|
||||
export default function ({ params: { websiteId } }) {
|
||||
export default async function ({ params }: { params: { websiteId: string } }) {
|
||||
const { websiteId } = await params;
|
||||
|
||||
return <SessionsPage websiteId={websiteId} />;
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { Metadata } from 'next';
|
||||
import Providers from './Providers';
|
||||
import '@fontsource/inter/300.css';
|
||||
import '@fontsource/inter/400.css';
|
||||
import '@fontsource/inter/500.css';
|
||||
import '@fontsource/inter/700.css';
|
||||
import '@fontsource/inter/800.css';
|
||||
import 'react-basics/dist/styles.css';
|
||||
import 'styles/index.css';
|
||||
import 'styles/variables.css';
|
||||
|
@ -1,5 +1,7 @@
|
||||
import SharePage from './SharePage';
|
||||
|
||||
export default function ({ params: { shareId } }) {
|
||||
export default async function ({ params }: { params: { shareId: string } }) {
|
||||
const { shareId } = await params;
|
||||
|
||||
return <SharePage shareId={shareId[0]} />;
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ export interface BarChartProps extends ChartProps {
|
||||
YAxisType?: string;
|
||||
minDate?: number | string;
|
||||
maxDate?: number | string;
|
||||
isAllTime?: boolean;
|
||||
}
|
||||
|
||||
export function BarChart(props: BarChartProps) {
|
||||
@ -29,6 +30,7 @@ export function BarChart(props: BarChartProps) {
|
||||
minDate,
|
||||
maxDate,
|
||||
currency,
|
||||
isAllTime,
|
||||
} = props;
|
||||
|
||||
const options: any = useMemo(() => {
|
||||
@ -37,7 +39,7 @@ export function BarChart(props: BarChartProps) {
|
||||
x: {
|
||||
type: XAxisType,
|
||||
stacked: true,
|
||||
min: minDate && new Date(minDate).getSeconds() === 0 ? minDate : '',
|
||||
min: isAllTime ? '' : minDate,
|
||||
max: maxDate,
|
||||
time: {
|
||||
unit,
|
||||
|
@ -1,5 +1,5 @@
|
||||
function getHostName(url: string) {
|
||||
const match = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?(?:www\.)?([^:/\n?=]+)/im);
|
||||
const match = url.match(/^(?:https?:\/\/)?(?:[^@\n]+@)?([^:/\n?=]+)/im);
|
||||
return match && match.length > 1 ? match[1] : null;
|
||||
}
|
||||
|
||||
|
@ -12,9 +12,12 @@ export function TypeIcon({
|
||||
return (
|
||||
<>
|
||||
<img
|
||||
src={`${process.env.basePath || ''}/images/${type}/${
|
||||
value?.replaceAll(' ', '-').toLowerCase() || 'unknown'
|
||||
}.png`}
|
||||
src={`${process.env.basePath || ''}/images/${type}/${value
|
||||
?.replaceAll(' ', '-')
|
||||
.toLowerCase()}.png`}
|
||||
onError={e => {
|
||||
e.currentTarget.src = `${process.env.basePath || ''}/images/${type}/unknown.png`;
|
||||
}}
|
||||
alt={value}
|
||||
width={type === 'country' ? undefined : 16}
|
||||
height={type === 'country' ? undefined : 16}
|
||||
|
@ -1,4 +1,6 @@
|
||||
import { useApi } from '../useApi';
|
||||
import { useCountryNames, useRegionNames } from 'components/hooks';
|
||||
import useLocale from '../useLocale';
|
||||
|
||||
export function useWebsiteValues({
|
||||
websiteId,
|
||||
@ -14,6 +16,36 @@ export function useWebsiteValues({
|
||||
search?: string;
|
||||
}) {
|
||||
const { get, useQuery } = useApi();
|
||||
const { locale } = useLocale();
|
||||
const { countryNames } = useCountryNames(locale);
|
||||
const { regionNames } = useRegionNames(locale);
|
||||
|
||||
const names = {
|
||||
country: countryNames,
|
||||
region: regionNames,
|
||||
};
|
||||
|
||||
const getSearch = (type: string, value: string) => {
|
||||
if (value) {
|
||||
const values = names[type];
|
||||
|
||||
if (values) {
|
||||
return (
|
||||
Object.keys(values)
|
||||
.reduce((arr: string[], key: string) => {
|
||||
if (values[key].toLowerCase().includes(value.toLowerCase())) {
|
||||
return arr.concat(key);
|
||||
}
|
||||
return arr;
|
||||
}, [])
|
||||
.slice(0, 5)
|
||||
.join(',') || value
|
||||
);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['websites:values', { websiteId, type, startDate, endDate, search }],
|
||||
@ -22,7 +54,7 @@ export function useWebsiteValues({
|
||||
type,
|
||||
startAt: +startDate,
|
||||
endAt: +endDate,
|
||||
search,
|
||||
search: getSearch(type, search),
|
||||
}),
|
||||
enabled: !!(websiteId && type && startDate && endDate),
|
||||
});
|
||||
|
@ -2,12 +2,14 @@ import useMessages from './useMessages';
|
||||
import { BROWSERS, OS_NAMES } from 'lib/constants';
|
||||
import useLocale from './useLocale';
|
||||
import useCountryNames from './useCountryNames';
|
||||
import useLanguageNames from './useLanguageNames';
|
||||
import regions from '../../../public/iso-3166-2.json';
|
||||
|
||||
export function useFormat() {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { locale } = useLocale();
|
||||
const { countryNames } = useCountryNames(locale);
|
||||
const { languageNames } = useLanguageNames(locale);
|
||||
|
||||
const formatOS = (value: string): string => {
|
||||
return OS_NAMES[value] || value;
|
||||
@ -34,6 +36,10 @@ export function useFormat() {
|
||||
return countryNames[country] ? `${value}, ${countryNames[country]}` : value;
|
||||
};
|
||||
|
||||
const formatLanguage = (value: string): string => {
|
||||
return languageNames[value?.split('-')[0]] || value;
|
||||
};
|
||||
|
||||
const formatValue = (value: string, type: string, data?: { [key: string]: any }): string => {
|
||||
switch (type) {
|
||||
case 'os':
|
||||
@ -48,12 +54,23 @@ export function useFormat() {
|
||||
return formatRegion(value);
|
||||
case 'city':
|
||||
return formatCity(value, data?.country);
|
||||
case 'language':
|
||||
return formatLanguage(value);
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
return { formatOS, formatBrowser, formatDevice, formatCountry, formatRegion, formatValue };
|
||||
return {
|
||||
formatOS,
|
||||
formatBrowser,
|
||||
formatDevice,
|
||||
formatCountry,
|
||||
formatRegion,
|
||||
formatCity,
|
||||
formatLanguage,
|
||||
formatValue,
|
||||
};
|
||||
}
|
||||
|
||||
export default useFormat;
|
||||
|
@ -28,7 +28,7 @@ export function useLanguageNames(locale) {
|
||||
}
|
||||
}, [locale]);
|
||||
|
||||
return list;
|
||||
return { languageNames: list };
|
||||
}
|
||||
|
||||
export default useLanguageNames;
|
||||
|
@ -1,25 +1,24 @@
|
||||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import { emptyFilter } from 'lib/filters';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import TypeIcon from 'components/common/TypeIcon';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useCountryNames } from 'components/hooks';
|
||||
import { useFormat } from 'components/hooks';
|
||||
|
||||
export function CitiesTable(props: MetricsTableProps) {
|
||||
const { locale } = useLocale();
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { countryNames } = useCountryNames(locale);
|
||||
|
||||
const renderLabel = (city: string, country: string) => {
|
||||
const countryName = countryNames[country];
|
||||
return countryName ? `${city}, ${countryName}` : city;
|
||||
};
|
||||
const { formatCity } = useFormat();
|
||||
|
||||
const renderLink = ({ x: city, country }) => {
|
||||
return (
|
||||
<FilterLink id="city" value={city} label={renderLabel(city, country)}>
|
||||
{country && <TypeIcon type="country" value={country} />}
|
||||
<FilterLink id="city" value={city} label={formatCity(city, country)}>
|
||||
{country && (
|
||||
<img
|
||||
src={`${process.env.basePath || ''}/images/country/${
|
||||
country?.toLowerCase() || 'xx'
|
||||
}.png`}
|
||||
alt={country}
|
||||
/>
|
||||
)}
|
||||
</FilterLink>
|
||||
);
|
||||
};
|
||||
@ -32,6 +31,7 @@ export function CitiesTable(props: MetricsTableProps) {
|
||||
metric={formatMessage(labels.visitors)}
|
||||
dataFilter={emptyFilter}
|
||||
renderLabel={renderLink}
|
||||
searchFormattedValues={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -12,7 +12,11 @@ export function CountriesTable({ ...props }: MetricsTableProps) {
|
||||
|
||||
const renderLink = ({ x: code }) => {
|
||||
return (
|
||||
<FilterLink id="country" value={countryNames[code] && code} label={formatCountry(code)}>
|
||||
<FilterLink
|
||||
id="country"
|
||||
value={(countryNames[code] && code) || code}
|
||||
label={formatCountry(code)}
|
||||
>
|
||||
<TypeIcon type="country" value={code?.toLowerCase()} />
|
||||
</FilterLink>
|
||||
);
|
||||
@ -25,6 +29,7 @@ export function CountriesTable({ ...props }: MetricsTableProps) {
|
||||
type="country"
|
||||
metric={formatMessage(labels.visitors)}
|
||||
renderLabel={renderLink}
|
||||
searchFormattedValues={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ export function DevicesTable(props: MetricsTableProps) {
|
||||
type="device"
|
||||
metric={formatMessage(labels.visitors)}
|
||||
renderLabel={renderLink}
|
||||
searchFormattedValues={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { useMemo } from 'react';
|
||||
import { colord } from 'colord';
|
||||
import BarChart from 'components/charts/BarChart';
|
||||
import { useLocale, useDateRange, useWebsiteEventsSeries } from 'components/hooks';
|
||||
import { CHART_COLORS } from 'lib/constants';
|
||||
import { useDateRange, useLocale, useWebsiteEventsSeries } from 'components/hooks';
|
||||
import { renderDateLabels } from 'lib/charts';
|
||||
import { CHART_COLORS } from 'lib/constants';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export interface EventsChartProps {
|
||||
websiteId: string;
|
||||
@ -12,7 +12,7 @@ export interface EventsChartProps {
|
||||
|
||||
export function EventsChart({ websiteId, className }: EventsChartProps) {
|
||||
const {
|
||||
dateRange: { startDate, endDate, unit },
|
||||
dateRange: { startDate, endDate, unit, value },
|
||||
} = useDateRange(websiteId);
|
||||
const { locale } = useLocale();
|
||||
const { data, isLoading } = useWebsiteEventsSeries(websiteId);
|
||||
@ -55,6 +55,7 @@ export function EventsChart({ websiteId, className }: EventsChartProps) {
|
||||
stacked={true}
|
||||
renderXLabel={renderDateLabels(unit, locale)}
|
||||
isLoading={isLoading}
|
||||
isAllTime={value === 'all'}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import { percentFilter } from 'lib/filters';
|
||||
import { useLanguageNames } from 'components/hooks';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useFormat } from 'components/hooks';
|
||||
|
||||
export function LanguagesTable({
|
||||
onDataLoad,
|
||||
@ -10,10 +10,10 @@ export function LanguagesTable({
|
||||
}: { onDataLoad: (data: any) => void } & MetricsTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { locale } = useLocale();
|
||||
const languageNames = useLanguageNames(locale);
|
||||
const { formatLanguage } = useFormat();
|
||||
|
||||
const renderLabel = ({ x }) => {
|
||||
return languageNames[x?.split('-')[0]] ?? x;
|
||||
return <div className={locale}>{formatLanguage(x)}</div>;
|
||||
};
|
||||
|
||||
return (
|
||||
@ -24,6 +24,7 @@ export function LanguagesTable({
|
||||
metric={formatMessage(labels.visitors)}
|
||||
onDataLoad={data => onDataLoad?.(percentFilter(data))}
|
||||
renderLabel={renderLabel}
|
||||
searchFormattedValues={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ export interface MetricsTableProps extends ListTableProps {
|
||||
onDataLoad?: (data: any) => void;
|
||||
onSearch?: (search: string) => void;
|
||||
allowSearch?: boolean;
|
||||
searchFormattedValues?: boolean;
|
||||
showMore?: boolean;
|
||||
params?: { [key: string]: any };
|
||||
children?: ReactNode;
|
||||
@ -40,6 +41,7 @@ export function MetricsTable({
|
||||
onDataLoad,
|
||||
delay = null,
|
||||
allowSearch = false,
|
||||
searchFormattedValues = false,
|
||||
showMore = true,
|
||||
params,
|
||||
children,
|
||||
@ -53,7 +55,7 @@ export function MetricsTable({
|
||||
|
||||
const { data, isLoading, isFetched, error } = useWebsiteMetrics(
|
||||
websiteId,
|
||||
{ type, limit, search, ...params },
|
||||
{ type, limit, search: searchFormattedValues ? undefined : search, ...params },
|
||||
{
|
||||
retryDelay: delay || DEFAULT_ANIMATION_DURATION,
|
||||
onDataLoad,
|
||||
@ -74,6 +76,14 @@ export function MetricsTable({
|
||||
}
|
||||
}
|
||||
|
||||
if (searchFormattedValues && search) {
|
||||
items = items.filter(({ x, ...data }) => {
|
||||
const value = formatValue(x, type, data);
|
||||
|
||||
return value?.toLowerCase().includes(search.toLowerCase());
|
||||
});
|
||||
}
|
||||
|
||||
items = percentFilter(items);
|
||||
|
||||
return items;
|
||||
|
@ -14,9 +14,16 @@ export interface PagepageviewsChartProps extends BarChartProps {
|
||||
};
|
||||
unit: string;
|
||||
isLoading?: boolean;
|
||||
isAllTime?: boolean;
|
||||
}
|
||||
|
||||
export function PagepageviewsChart({ data, unit, isLoading, ...props }: PagepageviewsChartProps) {
|
||||
export function PagepageviewsChart({
|
||||
data,
|
||||
unit,
|
||||
isLoading,
|
||||
isAllTime,
|
||||
...props
|
||||
}: PagepageviewsChartProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { colors } = useTheme();
|
||||
const { locale } = useLocale();
|
||||
@ -74,6 +81,7 @@ export function PagepageviewsChart({ data, unit, isLoading, ...props }: Pagepage
|
||||
data={chartData}
|
||||
unit={unit}
|
||||
isLoading={isLoading}
|
||||
isAllTime={isAllTime}
|
||||
renderXLabel={renderDateLabels(unit, locale)}
|
||||
/>
|
||||
);
|
||||
|
@ -25,6 +25,7 @@ export function RegionsTable(props: MetricsTableProps) {
|
||||
metric={formatMessage(labels.visitors)}
|
||||
dataFilter={emptyFilter}
|
||||
renderLabel={renderLink}
|
||||
searchFormattedValues={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -229,7 +229,7 @@
|
||||
"label.views-per-visit": "訪問あたりの閲覧数",
|
||||
"label.visit-duration": "平均滞在時間",
|
||||
"label.visitors": "訪問者",
|
||||
"label.visits": "訪問者数",
|
||||
"label.visits": "訪問数",
|
||||
"label.website": "Webサイト",
|
||||
"label.website-id": "WebサイトID",
|
||||
"label.websites": "Webサイト",
|
||||
|
@ -1,51 +1,51 @@
|
||||
{
|
||||
"label.access-code": "Access code",
|
||||
"label.access-code": "Tilgangskode",
|
||||
"label.actions": "Handlinger",
|
||||
"label.activity": "Activity log",
|
||||
"label.add": "Add",
|
||||
"label.add-description": "Add description",
|
||||
"label.add-member": "Add member",
|
||||
"label.add-step": "Add step",
|
||||
"label.activity": "Aktivitetslogg",
|
||||
"label.add": "Legg til",
|
||||
"label.add-description": "Legg til beskrivelse",
|
||||
"label.add-member": "Legg til bruker",
|
||||
"label.add-step": "Legg til steg",
|
||||
"label.add-website": "Legg til nettsted",
|
||||
"label.admin": "Administrator",
|
||||
"label.after": "After",
|
||||
"label.after": "Etter",
|
||||
"label.all": "Alle",
|
||||
"label.all-time": "Noensinne",
|
||||
"label.analytics": "Analytics",
|
||||
"label.average": "Average",
|
||||
"label.average": "Gjennomsnnitt",
|
||||
"label.back": "Tilbake",
|
||||
"label.before": "Before",
|
||||
"label.before": "Før",
|
||||
"label.bounce-rate": "Avvisningsfrekvens",
|
||||
"label.breakdown": "Breakdown",
|
||||
"label.browser": "Browser",
|
||||
"label.breakdown": "Nedbrytning",
|
||||
"label.browser": "Nettleser",
|
||||
"label.browsers": "Nettlesere",
|
||||
"label.cancel": "Avvis",
|
||||
"label.change-password": "Bytt passord",
|
||||
"label.cities": "Cities",
|
||||
"label.city": "City",
|
||||
"label.clear-all": "Clear all",
|
||||
"label.compare": "Compare",
|
||||
"label.confirm": "Confirm",
|
||||
"label.cities": "Byer",
|
||||
"label.city": "By",
|
||||
"label.clear-all": "Tøm alle",
|
||||
"label.compare": "Sammenlign",
|
||||
"label.confirm": "Bekreft",
|
||||
"label.confirm-password": "Godkjenn passord",
|
||||
"label.contains": "Contains",
|
||||
"label.continue": "Continue",
|
||||
"label.count": "Count",
|
||||
"label.contains": "Inneholder",
|
||||
"label.continue": "Fortsett",
|
||||
"label.count": "Antall",
|
||||
"label.countries": "Land",
|
||||
"label.country": "Country",
|
||||
"label.create": "Create",
|
||||
"label.create-report": "Create report",
|
||||
"label.create-team": "Create team",
|
||||
"label.create-user": "Create user",
|
||||
"label.created": "Created",
|
||||
"label.created-by": "Created By",
|
||||
"label.current": "Current",
|
||||
"label.country": "Land",
|
||||
"label.create": "Opprett",
|
||||
"label.create-report": "Opprett rapport",
|
||||
"label.create-team": "Opprett team",
|
||||
"label.create-user": "Opprett bruker",
|
||||
"label.created": "Opprettet",
|
||||
"label.created-by": "Opprettet av",
|
||||
"label.current": "Nåværende",
|
||||
"label.current-password": "Nåværende passord",
|
||||
"label.custom-range": "Egendefinert utvalg",
|
||||
"label.dashboard": "Dashbord",
|
||||
"label.data": "Data",
|
||||
"label.date": "Date",
|
||||
"label.date": "Dato",
|
||||
"label.date-range": "Datointervall",
|
||||
"label.day": "Day",
|
||||
"label.day": "Dag",
|
||||
"label.default-date-range": "Standard datoperiode",
|
||||
"label.delete": "Slett",
|
||||
"label.delete-report": "Delete report",
|
||||
@ -54,226 +54,227 @@
|
||||
"label.delete-website": "Slett nettstedet",
|
||||
"label.description": "Description",
|
||||
"label.desktop": "Stasjonær",
|
||||
"label.details": "Details",
|
||||
"label.device": "Device",
|
||||
"label.details": "Detaljer",
|
||||
"label.device": "Enhet",
|
||||
"label.devices": "Enheter",
|
||||
"label.dismiss": "Avbryt",
|
||||
"label.does-not-contain": "Does not contain",
|
||||
"label.does-not-contain": "Innholder ikke",
|
||||
"label.domain": "Domene",
|
||||
"label.dropoff": "Dropoff",
|
||||
"label.edit": "Rediger",
|
||||
"label.edit-dashboard": "Edit dashboard",
|
||||
"label.edit-member": "Edit member",
|
||||
"label.edit-dashboard": "Rediger dashboard",
|
||||
"label.edit-member": "Rediger bruker",
|
||||
"label.enable-share-url": "Aktiver delings-URL",
|
||||
"label.end-step": "End Step",
|
||||
"label.entry": "Entry URL",
|
||||
"label.event": "Event",
|
||||
"label.event-data": "Event data",
|
||||
"label.events": "Arrangementer",
|
||||
"label.exit": "Exit URL",
|
||||
"label.false": "False",
|
||||
"label.field": "Field",
|
||||
"label.fields": "Fields",
|
||||
"label.end-step": "Avslutt steg",
|
||||
"label.entry": "Inngangs-URL",
|
||||
"label.event": "Hendelse",
|
||||
"label.event-data": "Hendelsesdata",
|
||||
"label.events": "Hendelser",
|
||||
"label.exit": "Utgangs-URL",
|
||||
"label.false": "Usant",
|
||||
"label.field": "Felt",
|
||||
"label.fields": "Felt",
|
||||
"label.filter": "Filter",
|
||||
"label.filter-combined": "Kombinert",
|
||||
"label.filter-raw": "Rå",
|
||||
"label.filters": "Filters",
|
||||
"label.first-seen": "First seen",
|
||||
"label.funnel": "Funnel",
|
||||
"label.funnel-description": "Understand the conversion and drop-off rate of users.",
|
||||
"label.goal": "Goal",
|
||||
"label.goals": "Goals",
|
||||
"label.goals-description": "Track your goals for pageviews and events.",
|
||||
"label.greater-than": "Greater than",
|
||||
"label.greater-than-equals": "Greater than or equals",
|
||||
"label.host": "Host",
|
||||
"label.hosts": "Hosts",
|
||||
"label.insights": "Insights",
|
||||
"label.insights-description": "Dive deeper into your data by using segments and filters.",
|
||||
"label.is": "Is",
|
||||
"label.is-not": "Is not",
|
||||
"label.is-not-set": "Is not set",
|
||||
"label.is-set": "Is set",
|
||||
"label.join": "Join",
|
||||
"label.join-team": "Join team",
|
||||
"label.journey": "Journey",
|
||||
"label.journey-description": "Understand how users navigate through your website.",
|
||||
"label.filters": "Filter",
|
||||
"label.first-seen": "Først sett",
|
||||
"label.funnel": "Trakt",
|
||||
"label.funnel-description": "Forstå konverteringen og drop-off frafallsfrekvens av brukere.",
|
||||
"label.goal": "Mål",
|
||||
"label.goals": "Mål",
|
||||
"label.goals-description": "Spor dine mål for sidevisninger og hendelser.",
|
||||
"label.greater-than": "Mer enn",
|
||||
"label.greater-than-equals": "Mer enn eller lik",
|
||||
"label.host": "Vert",
|
||||
"label.hosts": "Verter",
|
||||
"label.insights": "Innsikt",
|
||||
"label.insights-description": "Dykk dypere i din data ved bruk av segmentering og filtre.",
|
||||
"label.is": "Er",
|
||||
"label.is-not": "Er ikke",
|
||||
"label.is-not-set": "Er ikke satt",
|
||||
"label.is-set": "Er satt",
|
||||
"label.join": "Bli med",
|
||||
"label.join-team": "Bli med i teamet",
|
||||
"label.journey": "Reise",
|
||||
"label.journey-description": "Forstå hvordan brukerene navigerer gjennom din side.",
|
||||
"label.language": "Språk",
|
||||
"label.languages": "Språk",
|
||||
"label.laptop": "Bærbar",
|
||||
"label.last-days": "Siste {x} dager",
|
||||
"label.last-hours": "Siste {x} timer",
|
||||
"label.last-months": "Last {x} months",
|
||||
"label.last-seen": "Last seen",
|
||||
"label.leave": "Leave",
|
||||
"label.leave-team": "Leave team",
|
||||
"label.less-than": "Less than",
|
||||
"label.less-than-equals": "Less than or equals",
|
||||
"label.last-seen": "Sist sett",
|
||||
"label.leave": "Forlat",
|
||||
"label.leave-team": "Forlat team",
|
||||
"label.less-than": "Mindre enn",
|
||||
"label.less-than-equals": "Mindre enn eller lik",
|
||||
"label.login": "Logg inn",
|
||||
"label.logout": "Logg ut",
|
||||
"label.manage": "Manage",
|
||||
"label.manager": "Manager",
|
||||
"label.max": "Max",
|
||||
"label.member": "Member",
|
||||
"label.members": "Members",
|
||||
"label.manage": "Administrer",
|
||||
"label.manager": "Administrator",
|
||||
"label.max": "Maks",
|
||||
"label.member": "Bruker",
|
||||
"label.members": "Brukere",
|
||||
"label.min": "Min",
|
||||
"label.mobile": "Mobiltelefon",
|
||||
"label.more": "Mer",
|
||||
"label.my-account": "My account",
|
||||
"label.my-websites": "My websites",
|
||||
"label.my-account": "Min konto",
|
||||
"label.my-websites": "Mine nettsider",
|
||||
"label.name": "Navn",
|
||||
"label.new-password": "Nytt passord",
|
||||
"label.none": "None",
|
||||
"label.none": "Ingen",
|
||||
"label.number-of-records": "{x} {x, plural, one {record} other {records}}",
|
||||
"label.ok": "OK",
|
||||
"label.os": "OS",
|
||||
"label.overview": "Overview",
|
||||
"label.overview": "Oversikt",
|
||||
"label.owner": "Eier",
|
||||
"label.page-of": "Page {current} of {total}",
|
||||
"label.page-of": "Side {current} av {total}",
|
||||
"label.page-views": "Sidevisninger",
|
||||
"label.pageTitle": "Page title",
|
||||
"label.pageTitle": "Sidetittel",
|
||||
"label.pages": "Sider",
|
||||
"label.password": "Passord",
|
||||
"label.path": "Path",
|
||||
"label.paths": "Paths",
|
||||
"label.path": "Sti",
|
||||
"label.paths": "Stier",
|
||||
"label.powered-by": "Drevet av {name}",
|
||||
"label.previous": "Previous",
|
||||
"label.previous-period": "Previous period",
|
||||
"label.previous-year": "Previous year",
|
||||
"label.previous": "Forrige",
|
||||
"label.previous-period": "Forrige periode",
|
||||
"label.previous-year": "Forrige år",
|
||||
"label.profile": "Profil",
|
||||
"label.properties": "Properties",
|
||||
"label.property": "Property",
|
||||
"label.queries": "Queries",
|
||||
"label.query": "Query",
|
||||
"label.query-parameters": "Query parameters",
|
||||
"label.properties": "Egenskaper",
|
||||
"label.property": "Egenskap",
|
||||
"label.queries": "Forspørsler",
|
||||
"label.query": "Forespørsel",
|
||||
"label.query-parameters": "Forespørsel parametere",
|
||||
"label.realtime": "Sanntid",
|
||||
"label.referrer": "Referrer",
|
||||
"label.referrers": "Referanser",
|
||||
"label.referrer": "Henviser",
|
||||
"label.referrers": "Henvisere",
|
||||
"label.refresh": "Oppdater",
|
||||
"label.regenerate": "Regenerate",
|
||||
"label.regenerate": "Regenerer",
|
||||
"label.region": "Region",
|
||||
"label.regions": "Regions",
|
||||
"label.remove": "Remove",
|
||||
"label.remove-member": "Remove member",
|
||||
"label.reports": "Reports",
|
||||
"label.regions": "Regioner",
|
||||
"label.remove": "Fjern",
|
||||
"label.remove-member": "Fjern bruker",
|
||||
"label.reports": "Rapporter",
|
||||
"label.required": "Påkrevd",
|
||||
"label.reset": "Nullstill",
|
||||
"label.reset-website": "Nullstill statistikk",
|
||||
"label.retention": "Retention",
|
||||
"label.retention-description": "Measure your website stickiness by tracking how often users return.",
|
||||
"label.revenue": "Revenue",
|
||||
"label.revenue-description": "Look into your revenue across time.",
|
||||
"label.revenue-property": "Revenue Property",
|
||||
"label.role": "Role",
|
||||
"label.run-query": "Run query",
|
||||
"label.retention": "Retensjon",
|
||||
"label.retention-description": "Mål nettstedets klebrighet ved å spore hvor ofte brukere kommer tilbake.",
|
||||
"label.revenue": "Inntenker",
|
||||
"label.revenue-description": "Se på inntektene dine over tid.",
|
||||
"label.revenue-property": "Inntektegenskaper",
|
||||
"label.role": "Rolle",
|
||||
"label.run-query": "Kjør spørring",
|
||||
"label.save": "Lagre",
|
||||
"label.screens": "Screens",
|
||||
"label.search": "Search",
|
||||
"label.select": "Select",
|
||||
"label.select-date": "Select date",
|
||||
"label.select-role": "Select role",
|
||||
"label.select-website": "Select website",
|
||||
"label.session": "Session",
|
||||
"label.sessions": "Sessions",
|
||||
"label.screens": "Skjermer",
|
||||
"label.search": "Søk",
|
||||
"label.select": "Velg",
|
||||
"label.select-date": "Velg dato",
|
||||
"label.select-role": "Velg rolle",
|
||||
"label.select-website": "Velg nettsted",
|
||||
"label.session": "Økt",
|
||||
"label.sessions": "Økter",
|
||||
"label.settings": "Innstillinger",
|
||||
"label.share-url": "Del URL",
|
||||
"label.single-day": "Enkelt dag",
|
||||
"label.start-step": "Start Step",
|
||||
"label.steps": "Steps",
|
||||
"label.single-day": "Enkeltdag",
|
||||
"label.start-step": "Starttrinn",
|
||||
"label.steps": "Trinn",
|
||||
"label.sum": "Sum",
|
||||
"label.tablet": "Nettbrett",
|
||||
"label.team": "Team",
|
||||
"label.team-id": "Team ID",
|
||||
"label.team-manager": "Team manager",
|
||||
"label.team-member": "Team member",
|
||||
"label.team-name": "Team name",
|
||||
"label.team-owner": "Team owner",
|
||||
"label.team-view-only": "Team view only",
|
||||
"label.team-websites": "Team websites",
|
||||
"label.teams": "Teams",
|
||||
"label.theme": "Theme",
|
||||
"label.team-id": "Team-ID",
|
||||
"label.team-manager": "Teamadministrator",
|
||||
"label.team-member": "Teammedlem",
|
||||
"label.team-name": "Teamnavn",
|
||||
"label.team-owner": "Teameier",
|
||||
"label.team-view-only": "Team (kun visning)",
|
||||
"label.team-websites": "Team-nettsteder",
|
||||
"label.teams": "Team",
|
||||
"label.theme": "Tema",
|
||||
"label.this-month": "Denne måneden",
|
||||
"label.this-week": "Denne uka",
|
||||
"label.this-year": "I år",
|
||||
"label.timezone": "Tidssone",
|
||||
"label.title": "Title",
|
||||
"label.title": "Tittel",
|
||||
"label.today": "I dag",
|
||||
"label.toggle-charts": "Veksle grafer",
|
||||
"label.total": "Total",
|
||||
"label.total-records": "Total records",
|
||||
"label.total": "Totalt",
|
||||
"label.total-records": "Totalt antall oppføringer",
|
||||
"label.tracking-code": "Sporingskode",
|
||||
"label.transactions": "Transactions",
|
||||
"label.transfer": "Transfer",
|
||||
"label.transfer-website": "Transfer website",
|
||||
"label.true": "True",
|
||||
"label.transactions": "Transaksjoner",
|
||||
"label.transfer": "Overfør",
|
||||
"label.transfer-website": "Overfør nettsted",
|
||||
"label.true": "Sant",
|
||||
"label.type": "Type",
|
||||
"label.unique": "Unique",
|
||||
"label.unique": "Unike",
|
||||
"label.unique-visitors": "Unike besøkende",
|
||||
"label.uniqueCustomers": "Unique Customers",
|
||||
"label.uniqueCustomers": "Unike kunder",
|
||||
"label.unknown": "Ukjent",
|
||||
"label.untitled": "Untitled",
|
||||
"label.update": "Update",
|
||||
"label.untitled": "Uten tittel",
|
||||
"label.update": "Oppdater",
|
||||
"label.url": "URL",
|
||||
"label.urls": "URLs",
|
||||
"label.user": "User",
|
||||
"label.user-property": "User Property",
|
||||
"label.urls": "URL-er",
|
||||
"label.user": "Bruker",
|
||||
"label.user-property": "Brukeregenskap",
|
||||
"label.username": "Brukernavn",
|
||||
"label.users": "Users",
|
||||
"label.users": "Brukere",
|
||||
"label.utm": "UTM",
|
||||
"label.utm-description": "Track your campaigns through UTM parameters.",
|
||||
"label.value": "Value",
|
||||
"label.view": "View",
|
||||
"label.utm-description": "Spor kampanjene dine via UTM-parametre.",
|
||||
"label.value": "Verdi",
|
||||
"label.view": "Vis",
|
||||
"label.view-details": "Vis detaljer",
|
||||
"label.view-only": "View only",
|
||||
"label.view-only": "Kun visning",
|
||||
"label.views": "Visninger",
|
||||
"label.views-per-visit": "Views per visit",
|
||||
"label.views-per-visit": "Visninger per besøk",
|
||||
"label.visit-duration": "Gjennomsnittlig besøkstid",
|
||||
"label.visitors": "Besøkende",
|
||||
"label.visits": "Visits",
|
||||
"label.website": "Website",
|
||||
"label.website-id": "Website ID",
|
||||
"label.visits": "Besøk",
|
||||
"label.website": "Nettsted",
|
||||
"label.website-id": "Nettsted-ID",
|
||||
"label.websites": "Nettsteder",
|
||||
"label.window": "Window",
|
||||
"label.yesterday": "Yesterday",
|
||||
"message.action-confirmation": "Type {confirmation} in the box below to confirm.",
|
||||
"label.window": "Vindu",
|
||||
"label.yesterday": "I går",
|
||||
"message.action-confirmation": "Skriv {confirmation} i feltet nedenfor for å bekrefte.",
|
||||
"message.active-users": "{x} {x, plural, one {besøkende} other {besøkende}} nå",
|
||||
"message.collected-data": "Collected data",
|
||||
"message.collected-data": "Innsamlede data",
|
||||
"message.confirm-delete": "Er du sikker på at du vil slette {target}?",
|
||||
"message.confirm-leave": "Are you sure you want to leave {target}?",
|
||||
"message.confirm-remove": "Are you sure you want to remove {target}?",
|
||||
"message.confirm-reset": "Er du sikker på at du vil nullstille {target}'s statistikk?",
|
||||
"message.delete-team-warning": "Deleting a team will also delete all team websites.",
|
||||
"message.delete-website-warning": "Alle tilknyttede data slettes også.",
|
||||
"message.confirm-leave": "Er du sikker på at du vil forlate {target}?",
|
||||
"message.confirm-remove": "Er du sikker på at du vil fjerne {target}?",
|
||||
"message.confirm-reset": "Er du sikker på at du vil nullstille statistikken til {target}?",
|
||||
"message.delete-team-warning": "Å slette et team vil også slette alle teamets nettsteder.",
|
||||
"message.delete-website-warning": "Alle tilknyttede data vil også bli slettet.",
|
||||
"message.error": "Noe gikk galt.",
|
||||
"message.event-log": "{event} on {url}",
|
||||
"message.event-log": "{event} på {url}",
|
||||
"message.go-to-settings": "Gå til innstillinger",
|
||||
"message.incorrect-username-password": "Ugyldig brukernavn/passord.",
|
||||
"message.invalid-domain": "Ugyldig domene",
|
||||
"message.min-password-length": "Minimum length of {n} characters",
|
||||
"message.new-version-available": "A new version of Umami {version} is available!",
|
||||
"message.min-password-length": "Minimumslengde på {n} tegn",
|
||||
"message.new-version-available": "En ny versjon av Umami {version} er tilgjengelig!",
|
||||
"message.no-data-available": "Ingen data tilgjengelig.",
|
||||
"message.no-event-data": "No event data is available.",
|
||||
"message.no-event-data": "Ingen hendelsesdata er tilgjengelig.",
|
||||
"message.no-match-password": "Passordene er ikke like",
|
||||
"message.no-results-found": "No results were found.",
|
||||
"message.no-team-websites": "This team does not have any websites.",
|
||||
"message.no-teams": "You have not created any teams.",
|
||||
"message.no-users": "There are no users.",
|
||||
"message.no-results-found": "Ingen resultater funnet.",
|
||||
"message.no-team-websites": "Dette teamet har ingen nettsteder.",
|
||||
"message.no-teams": "Du har ikke opprettet noen team.",
|
||||
"message.no-users": "Ingen brukere.",
|
||||
"message.no-websites-configured": "Du har ikke satt opp noen nettsteder.",
|
||||
"message.page-not-found": "Side ikke funnet.",
|
||||
"message.reset-website": "To reset this website, type {confirmation} in the box below to confirm.",
|
||||
"message.reset-website-warning": "All statistikk for denne nettsiden vil bli slettet, men sporingskoden din vil forbli uberørt.",
|
||||
"message.page-not-found": "Siden ble ikke funnet.",
|
||||
"message.reset-website": "For å nullstille dette nettstedet, skriv {confirmation} i feltet nedenfor for å bekrefte.",
|
||||
"message.reset-website-warning": "All statistikk for dette nettstedet vil bli slettet, men sporingskoden forblir uberørt.",
|
||||
"message.saved": "Lagret!",
|
||||
"message.share-url": "Dette er den offentlige delings-URL-en for {target}.",
|
||||
"message.team-already-member": "You are already a member of the team.",
|
||||
"message.team-not-found": "Team not found.",
|
||||
"message.team-websites-info": "Websites can be viewed by anyone on the team.",
|
||||
"message.team-already-member": "Du er allerede medlem av teamet.",
|
||||
"message.team-not-found": "Teamet ble ikke funnet.",
|
||||
"message.team-websites-info": "Nettsteder kan vises av alle på teamet.",
|
||||
"message.tracking-code": "Sporingskode",
|
||||
"message.transfer-team-website-to-user": "Transfer this website to your account?",
|
||||
"message.transfer-user-website-to-team": "Select the team to transfer this website to.",
|
||||
"message.transfer-website": "Transfer website ownership to your account or another team.",
|
||||
"message.triggered-event": "Triggered event",
|
||||
"message.user-deleted": "User deleted.",
|
||||
"message.viewed-page": "Viewed page",
|
||||
"message.transfer-team-website-to-user": "Overfør dette nettstedet til kontoen din?",
|
||||
"message.transfer-user-website-to-team": "Velg teamet du vil overføre dette nettstedet til.",
|
||||
"message.transfer-website": "Overfør eierskapet til nettstedet til din konto eller et annet team.",
|
||||
"message.triggered-event": "Utløst hendelse",
|
||||
"message.user-deleted": "Bruker slettet.",
|
||||
"message.viewed-page": "Vist side",
|
||||
"message.visitor-log": "Besøkende fra {country} med {browser} på {os} {device}",
|
||||
"message.visitors-dropped-off": "Visitors dropped off"
|
||||
"message.visitors-dropped-off": "Besøkende falt fra"
|
||||
|
||||
}
|
||||
|
@ -78,7 +78,7 @@
|
||||
"label.filter-combined": "合并",
|
||||
"label.filter-raw": "原始",
|
||||
"label.filters": "筛选",
|
||||
"label.first-seen": "First seen",
|
||||
"label.first-seen": "首次出现",
|
||||
"label.funnel": "分析",
|
||||
"label.funnel-description": "了解用户的转换率和退出率。",
|
||||
"label.goal": "目标",
|
||||
@ -104,7 +104,7 @@
|
||||
"label.last-days": "最近 {x} 天",
|
||||
"label.last-hours": "最近 {x} 小时",
|
||||
"label.last-months": "最近 {x} 个月",
|
||||
"label.last-seen": "Last seen",
|
||||
"label.last-seen": "最后出现",
|
||||
"label.leave": "离开",
|
||||
"label.leave-team": "离开团队",
|
||||
"label.less-than": "少于",
|
||||
@ -161,9 +161,9 @@
|
||||
"label.reset-website": "重置统计数据",
|
||||
"label.retention": "保留",
|
||||
"label.retention-description": "通过跟踪用户返回的频率来衡量网站的用户粘性。",
|
||||
"label.revenue": "Revenue",
|
||||
"label.revenue-description": "Look into your revenue across time.",
|
||||
"label.revenue-property": "Revenue Property",
|
||||
"label.revenue": "收入",
|
||||
"label.revenue-description": "查看您的收入随时间的变化。",
|
||||
"label.revenue-property": "收入值",
|
||||
"label.role": "角色",
|
||||
"label.run-query": "查询",
|
||||
"label.save": "保存",
|
||||
@ -202,21 +202,21 @@
|
||||
"label.total": "总数",
|
||||
"label.total-records": "总记录数",
|
||||
"label.tracking-code": "跟踪代码",
|
||||
"label.transactions": "Transactions",
|
||||
"label.transactions": "交易",
|
||||
"label.transfer": "转移",
|
||||
"label.transfer-website": "转移网站",
|
||||
"label.true": "是",
|
||||
"label.type": "类型",
|
||||
"label.unique": "独立",
|
||||
"label.unique-visitors": "独立访客",
|
||||
"label.uniqueCustomers": "Unique Customers",
|
||||
"label.uniqueCustomers": "独特客户",
|
||||
"label.unknown": "未知",
|
||||
"label.untitled": "未命名",
|
||||
"label.update": "更新",
|
||||
"label.url": "网址",
|
||||
"label.urls": "网址",
|
||||
"label.user": "用户",
|
||||
"label.user-property": "User Property",
|
||||
"label.user-property": "用户属性",
|
||||
"label.username": "用户名",
|
||||
"label.users": "用户",
|
||||
"label.utm": "UTM",
|
||||
|
@ -1,11 +1,11 @@
|
||||
{
|
||||
"label.access-code": "存取碼",
|
||||
"label.actions": "行動",
|
||||
"label.activity": "活動日誌",
|
||||
"label.actions": "行為",
|
||||
"label.activity": "活動紀錄",
|
||||
"label.add": "新增",
|
||||
"label.add-description": "新增描述",
|
||||
"label.add-member": "Add member",
|
||||
"label.add-step": "Add step",
|
||||
"label.add-member": "新增成員",
|
||||
"label.add-step": "新增步驟",
|
||||
"label.add-website": "新增網站",
|
||||
"label.admin": "管理員",
|
||||
"label.after": "之後",
|
||||
@ -16,7 +16,7 @@
|
||||
"label.back": "返回",
|
||||
"label.before": "之前",
|
||||
"label.bounce-rate": "跳出率",
|
||||
"label.breakdown": "分解",
|
||||
"label.breakdown": "細項分析",
|
||||
"label.browser": "瀏覽器",
|
||||
"label.browsers": "瀏覽器",
|
||||
"label.cancel": "取消",
|
||||
@ -24,21 +24,21 @@
|
||||
"label.cities": "城市",
|
||||
"label.city": "城市",
|
||||
"label.clear-all": "全部清除",
|
||||
"label.compare": "Compare",
|
||||
"label.compare": "比較",
|
||||
"label.confirm": "確認",
|
||||
"label.confirm-password": "確認密碼",
|
||||
"label.contains": "包含",
|
||||
"label.continue": "繼續",
|
||||
"label.count": "Count",
|
||||
"label.count": "數量",
|
||||
"label.countries": "國家",
|
||||
"label.country": "國家",
|
||||
"label.create": "建立",
|
||||
"label.create-report": "建立報告",
|
||||
"label.create-report": "建立報表",
|
||||
"label.create-team": "建立團隊",
|
||||
"label.create-user": "建立使用者",
|
||||
"label.created": "已建立",
|
||||
"label.created-by": "Created By",
|
||||
"label.current": "Current",
|
||||
"label.created-by": "建立者",
|
||||
"label.current": "目前",
|
||||
"label.current-password": "目前密碼",
|
||||
"label.custom-range": "自訂範圍",
|
||||
"label.dashboard": "儀表板",
|
||||
@ -48,7 +48,7 @@
|
||||
"label.day": "日",
|
||||
"label.default-date-range": "預設日期範圍",
|
||||
"label.delete": "刪除",
|
||||
"label.delete-report": "Delete report",
|
||||
"label.delete-report": "刪除報表",
|
||||
"label.delete-team": "刪除團隊",
|
||||
"label.delete-user": "刪除使用者",
|
||||
"label.delete-website": "刪除網站",
|
||||
@ -60,89 +60,89 @@
|
||||
"label.dismiss": "關閉",
|
||||
"label.does-not-contain": "不包含",
|
||||
"label.domain": "網域",
|
||||
"label.dropoff": "退出",
|
||||
"label.dropoff": "離開",
|
||||
"label.edit": "編輯",
|
||||
"label.edit-dashboard": "編輯儀表板",
|
||||
"label.edit-member": "Edit member",
|
||||
"label.enable-share-url": "啟用分享網址",
|
||||
"label.end-step": "End Step",
|
||||
"label.entry": "Entry URL",
|
||||
"label.edit-member": "編輯成員",
|
||||
"label.enable-share-url": "啟用分享連結",
|
||||
"label.end-step": "結束步驟",
|
||||
"label.entry": "進入網址",
|
||||
"label.event": "事件",
|
||||
"label.event-data": "事件資料",
|
||||
"label.events": "事件",
|
||||
"label.exit": "Exit URL",
|
||||
"label.exit": "離開網址",
|
||||
"label.false": "否",
|
||||
"label.field": "欄位",
|
||||
"label.fields": "欄位",
|
||||
"label.filter": "篩選器",
|
||||
"label.filter-combined": "組合",
|
||||
"label.filter-raw": "原始",
|
||||
"label.filters": "篩選器",
|
||||
"label.first-seen": "First seen",
|
||||
"label.funnel": "漏斗",
|
||||
"label.funnel-description": "瞭解使用者的轉換率和退出率",
|
||||
"label.goal": "Goal",
|
||||
"label.goals": "Goals",
|
||||
"label.goals-description": "Track your goals for pageviews and events.",
|
||||
"label.filters": "篩選條件",
|
||||
"label.first-seen": "首次造訪",
|
||||
"label.funnel": "漏斗分析",
|
||||
"label.funnel-description": "瞭解使用者的轉換率與流失率。",
|
||||
"label.goal": "目標",
|
||||
"label.goals": "目標",
|
||||
"label.goals-description": "追蹤網頁瀏覽和事件的目標。",
|
||||
"label.greater-than": "大於",
|
||||
"label.greater-than-equals": "大於或等於",
|
||||
"label.host": "Host",
|
||||
"label.hosts": "Hosts",
|
||||
"label.host": "主機名稱",
|
||||
"label.hosts": "主機名稱",
|
||||
"label.insights": "洞察",
|
||||
"label.insights-description": "透過使用區段和篩選器來深入探索你的數據",
|
||||
"label.insights-description": "使用區段和篩選器來深入分析您的資料。",
|
||||
"label.is": "是",
|
||||
"label.is-not": "不是",
|
||||
"label.is-not-set": "未設定",
|
||||
"label.is-set": "已設定",
|
||||
"label.join": "加入",
|
||||
"label.join-team": "加入團隊",
|
||||
"label.journey": "Journey",
|
||||
"label.journey-description": "Understand how users navigate through your website.",
|
||||
"label.journey": "使用者旅程",
|
||||
"label.journey-description": "瞭解使用者如何瀏覽您的網站。",
|
||||
"label.language": "語言",
|
||||
"label.languages": "語言",
|
||||
"label.laptop": "筆記型電腦",
|
||||
"label.last-days": "最近 {x} 天",
|
||||
"label.last-hours": "最近 {x} 小時",
|
||||
"label.last-months": "Last {x} months",
|
||||
"label.last-seen": "Last seen",
|
||||
"label.last-months": "最近 {x} 個月",
|
||||
"label.last-seen": "最後造訪",
|
||||
"label.leave": "離開",
|
||||
"label.leave-team": "離開團隊",
|
||||
"label.less-than": "小於",
|
||||
"label.less-than-equals": "小於或等於",
|
||||
"label.login": "登入",
|
||||
"label.logout": "登出",
|
||||
"label.manage": "Manage",
|
||||
"label.manager": "Manager",
|
||||
"label.max": "最大",
|
||||
"label.member": "Member",
|
||||
"label.manage": "管理",
|
||||
"label.manager": "管理者",
|
||||
"label.max": "最大值",
|
||||
"label.member": "成員",
|
||||
"label.members": "成員",
|
||||
"label.min": "最小",
|
||||
"label.min": "最小值",
|
||||
"label.mobile": "行動裝置",
|
||||
"label.more": "更多",
|
||||
"label.my-account": "My account",
|
||||
"label.my-account": "我的帳號",
|
||||
"label.my-websites": "我的網站",
|
||||
"label.name": "名稱",
|
||||
"label.new-password": "新密碼",
|
||||
"label.none": "無",
|
||||
"label.number-of-records": "{x} {x, plural, one {record} other {records}}",
|
||||
"label.number-of-records": "{x} 筆紀錄",
|
||||
"label.ok": "OK",
|
||||
"label.os": "作業系統",
|
||||
"label.overview": "概覽",
|
||||
"label.overview": "總覽",
|
||||
"label.owner": "擁有者",
|
||||
"label.page-of": "頁面 {current} / {total}",
|
||||
"label.page-views": "頁面瀏覽",
|
||||
"label.pageTitle": "頁面標題",
|
||||
"label.pages": "頁面",
|
||||
"label.page-of": "第 {current} 頁,共 {total} 頁",
|
||||
"label.page-views": "網頁瀏覽次數",
|
||||
"label.pageTitle": "網頁標題",
|
||||
"label.pages": "網頁",
|
||||
"label.password": "密碼",
|
||||
"label.path": "Path",
|
||||
"label.paths": "Paths",
|
||||
"label.powered-by": "由 {name} 提供",
|
||||
"label.previous": "Previous",
|
||||
"label.previous-period": "Previous period",
|
||||
"label.previous-year": "Previous year",
|
||||
"label.profile": "個人資料",
|
||||
"label.properties": "Properties",
|
||||
"label.property": "Property",
|
||||
"label.path": "路徑",
|
||||
"label.paths": "路徑",
|
||||
"label.powered-by": "由 {name} 提供技術支援",
|
||||
"label.previous": "上一個",
|
||||
"label.previous-period": "上一期間",
|
||||
"label.previous-year": "去年",
|
||||
"label.profile": "個人檔案",
|
||||
"label.properties": "屬性",
|
||||
"label.property": "屬性",
|
||||
"label.queries": "查詢",
|
||||
"label.query": "查詢",
|
||||
"label.query-parameters": "查詢參數",
|
||||
@ -151,44 +151,44 @@
|
||||
"label.referrers": "參照來源",
|
||||
"label.refresh": "重新整理",
|
||||
"label.regenerate": "重新產生",
|
||||
"label.region": "區域",
|
||||
"label.regions": "區域",
|
||||
"label.region": "地區",
|
||||
"label.regions": "地區",
|
||||
"label.remove": "移除",
|
||||
"label.remove-member": "Remove member",
|
||||
"label.reports": "報告",
|
||||
"label.remove-member": "移除成員",
|
||||
"label.reports": "報表",
|
||||
"label.required": "必填",
|
||||
"label.reset": "重設",
|
||||
"label.reset-website": "重設網站",
|
||||
"label.retention": "保留",
|
||||
"label.reset-website": "重設網站統計資料",
|
||||
"label.retention": "留存率",
|
||||
"label.retention-description": "透過追蹤使用者回訪的頻率來衡量您的網站黏著度。",
|
||||
"label.revenue": "Revenue",
|
||||
"label.revenue-description": "Look into your revenue across time.",
|
||||
"label.revenue-property": "Revenue Property",
|
||||
"label.revenue": "營收",
|
||||
"label.revenue-description": "查看您的營收趨勢。",
|
||||
"label.revenue-property": "營收屬性",
|
||||
"label.role": "角色",
|
||||
"label.run-query": "執行查詢",
|
||||
"label.save": "儲存",
|
||||
"label.screens": "螢幕",
|
||||
"label.search": "Search",
|
||||
"label.select": "Select",
|
||||
"label.select-date": "選擇日期",
|
||||
"label.select-role": "Select role",
|
||||
"label.select-website": "選擇網站",
|
||||
"label.session": "Session",
|
||||
"label.search": "搜尋",
|
||||
"label.select": "選取",
|
||||
"label.select-date": "選取日期",
|
||||
"label.select-role": "選取角色",
|
||||
"label.select-website": "選取網站",
|
||||
"label.session": "工作階段",
|
||||
"label.sessions": "工作階段",
|
||||
"label.settings": "設定",
|
||||
"label.share-url": "分享網址",
|
||||
"label.share-url": "分享連結",
|
||||
"label.single-day": "單日",
|
||||
"label.start-step": "Start Step",
|
||||
"label.steps": "Steps",
|
||||
"label.start-step": "起始步驟",
|
||||
"label.steps": "步驟",
|
||||
"label.sum": "總和",
|
||||
"label.tablet": "平板",
|
||||
"label.team": "團隊",
|
||||
"label.team-id": "團隊 ID",
|
||||
"label.team-manager": "Team manager",
|
||||
"label.team-manager": "團隊管理者",
|
||||
"label.team-member": "團隊成員",
|
||||
"label.team-name": "團隊名稱",
|
||||
"label.team-owner": "團隊擁有者",
|
||||
"label.team-view-only": "Team view only",
|
||||
"label.team-view-only": "團隊僅供檢視",
|
||||
"label.team-websites": "團隊網站",
|
||||
"label.teams": "團隊",
|
||||
"label.theme": "主題",
|
||||
@ -200,80 +200,80 @@
|
||||
"label.today": "今天",
|
||||
"label.toggle-charts": "切換圖表",
|
||||
"label.total": "總計",
|
||||
"label.total-records": "總記錄",
|
||||
"label.total-records": "紀錄總數",
|
||||
"label.tracking-code": "追蹤代碼",
|
||||
"label.transactions": "Transactions",
|
||||
"label.transfer": "Transfer",
|
||||
"label.transfer-website": "Transfer website",
|
||||
"label.transactions": "交易",
|
||||
"label.transfer": "轉移",
|
||||
"label.transfer-website": "轉移網站",
|
||||
"label.true": "是",
|
||||
"label.type": "類型",
|
||||
"label.unique": "獨立",
|
||||
"label.unique-visitors": "獨立訪客",
|
||||
"label.uniqueCustomers": "Unique Customers",
|
||||
"label.unique": "不重複",
|
||||
"label.unique-visitors": "不重複訪客",
|
||||
"label.uniqueCustomers": "不重複客戶",
|
||||
"label.unknown": "未知",
|
||||
"label.untitled": "無標題",
|
||||
"label.update": "Update",
|
||||
"label.untitled": "未命名",
|
||||
"label.update": "更新",
|
||||
"label.url": "網址",
|
||||
"label.urls": "網址",
|
||||
"label.user": "使用者",
|
||||
"label.user-property": "User Property",
|
||||
"label.user-property": "使用者屬性",
|
||||
"label.username": "使用者名稱",
|
||||
"label.users": "使用者",
|
||||
"label.utm": "UTM",
|
||||
"label.utm-description": "Track your campaigns through UTM parameters.",
|
||||
"label.utm-description": "透過 UTM 參數追蹤您的行銷活動。",
|
||||
"label.value": "值",
|
||||
"label.view": "檢視",
|
||||
"label.view-details": "檢視詳細資訊",
|
||||
"label.view-only": "僅供檢視",
|
||||
"label.views": "檢視",
|
||||
"label.views-per-visit": "Views per visit",
|
||||
"label.visit-duration": "平均造訪時間",
|
||||
"label.views": "瀏覽次數",
|
||||
"label.views-per-visit": "每次造訪的瀏覽次數",
|
||||
"label.visit-duration": "造訪時間",
|
||||
"label.visitors": "訪客",
|
||||
"label.visits": "Visits",
|
||||
"label.visits": "造訪次數",
|
||||
"label.website": "網站",
|
||||
"label.website-id": "網站 ID",
|
||||
"label.websites": "網站",
|
||||
"label.window": "視窗",
|
||||
"label.yesterday": "昨天",
|
||||
"message.action-confirmation": "Type {confirmation} in the box below to confirm.",
|
||||
"message.active-users": "目前有 {x} 個活躍的訪客",
|
||||
"message.collected-data": "Collected data",
|
||||
"message.action-confirmation": "請在下方欄位輸入 {confirmation} 以確認。",
|
||||
"message.active-users": "目前有 {x} 位訪客",
|
||||
"message.collected-data": "已蒐集的資料",
|
||||
"message.confirm-delete": "您確定要刪除 {target} 嗎?",
|
||||
"message.confirm-leave": "您確定要離開 {target} 嗎?",
|
||||
"message.confirm-remove": "Are you sure you want to remove {target}?",
|
||||
"message.confirm-reset": "您確定要重設 {target} 嗎?",
|
||||
"message.delete-team-warning": "Deleting a team will also delete all team websites.",
|
||||
"message.delete-website-warning": "所有網站資料將被刪除。",
|
||||
"message.confirm-remove": "您確定要移除 {target} 嗎?",
|
||||
"message.confirm-reset": "您確定要重設 {target} 的統計資料嗎?",
|
||||
"message.delete-team-warning": "刪除團隊的同時也會刪除所有團隊的網站。",
|
||||
"message.delete-website-warning": "所有網站資料都將被刪除。",
|
||||
"message.error": "發生錯誤。",
|
||||
"message.event-log": "{event} 在 {url}",
|
||||
"message.event-log": "在 {url} 上的 {event}",
|
||||
"message.go-to-settings": "前往設定",
|
||||
"message.incorrect-username-password": "使用者名稱和/或密碼不正確。",
|
||||
"message.invalid-domain": "無效的網域。請不要包含 http/https。",
|
||||
"message.min-password-length": "最少需要 {n} 個字元",
|
||||
"message.new-version-available": "Umami {version} 的新版本已經可以使用!",
|
||||
"message.incorrect-username-password": "使用者名稱或密碼不正確。",
|
||||
"message.invalid-domain": "無效的網域。請勿包含 http/https。",
|
||||
"message.min-password-length": "密碼長度至少需 {n} 個字元",
|
||||
"message.new-version-available": "Umami {version} 的新版本已推出!",
|
||||
"message.no-data-available": "沒有可用的資料。",
|
||||
"message.no-event-data": "沒有可用的事件資料。",
|
||||
"message.no-match-password": "密碼不一致。",
|
||||
"message.no-results-found": "找不到結果。",
|
||||
"message.no-team-websites": "此團隊沒有任何網站。",
|
||||
"message.no-teams": "您尚未建立任何團隊。",
|
||||
"message.no-users": "沒有使用者。",
|
||||
"message.no-users": "沒有任何使用者。",
|
||||
"message.no-websites-configured": "您尚未設定任何網站。",
|
||||
"message.page-not-found": "找不到頁面",
|
||||
"message.reset-website": "要重設此網站,請在下方的方框中輸入 {confirmation} 以確認。",
|
||||
"message.reset-website-warning": "此網站的所有統計將被刪除,但您的設定將保持不變。",
|
||||
"message.page-not-found": "找不到網頁",
|
||||
"message.reset-website": "要重設此網站的統計資料,請在下方欄位輸入 {confirmation} 以確認。",
|
||||
"message.reset-website-warning": "此網站的所有統計資料都將被刪除,但您的設定將保持不變。",
|
||||
"message.saved": "已儲存。",
|
||||
"message.share-url": "您的網站統計資料可以在以下網址公開檢視:",
|
||||
"message.team-already-member": "您已經是團隊的成員。",
|
||||
"message.share-url": "您的網站統計資料可在以下網址公開檢視:",
|
||||
"message.team-already-member": "您已是該團隊的成員。",
|
||||
"message.team-not-found": "找不到團隊。",
|
||||
"message.team-websites-info": "團隊的任何成員都可以檢視網站。",
|
||||
"message.tracking-code": "要追蹤此網站的統計,請將以下代碼放在您的 HTML 的 <head>...</head> 區段中。",
|
||||
"message.transfer-team-website-to-user": "Transfer this website to your account?",
|
||||
"message.transfer-user-website-to-team": "Select the team to transfer this website to.",
|
||||
"message.transfer-website": "Transfer website ownership to your account or another team.",
|
||||
"message.triggered-event": "Triggered event",
|
||||
"message.team-websites-info": "團隊中的所有成員都可以檢視網站。",
|
||||
"message.tracking-code": "要追蹤此網站的統計資料,請將以下程式碼放在您 HTML 的 <head>...</head> 區段中。",
|
||||
"message.transfer-team-website-to-user": "要將此網站轉移至您的帳號嗎?",
|
||||
"message.transfer-user-website-to-team": "請選擇要轉移此網站的團隊。",
|
||||
"message.transfer-website": "將網站所有權轉移至您的帳號或其他團隊。",
|
||||
"message.triggered-event": "已觸發的事件",
|
||||
"message.user-deleted": "使用者已刪除。",
|
||||
"message.viewed-page": "Viewed page",
|
||||
"message.viewed-page": "已瀏覽的網頁",
|
||||
"message.visitor-log": "來自 {country} 的訪客在 {device} 上的 {os} 使用 {browser} 瀏覽。",
|
||||
"message.visitors-dropped-off": "Visitors dropped off"
|
||||
"message.visitors-dropped-off": "訪客已離開"
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Report } from '@prisma/client';
|
||||
import redis from '@umami/redis-client';
|
||||
import { getClient } from '@umami/redis-client';
|
||||
import debug from 'debug';
|
||||
import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER, ROLES } from 'lib/constants';
|
||||
import { PERMISSIONS, ROLE_PERMISSIONS, SHARE_TOKEN_HEADER } from 'lib/constants';
|
||||
import { secret } from 'lib/crypto';
|
||||
import { NextApiRequest } from 'next';
|
||||
import { createSecureToken, ensureArray, getRandomChars, parseToken } from 'next-basics';
|
||||
@ -14,10 +14,12 @@ const cloudMode = process.env.CLOUD_MODE;
|
||||
export async function saveAuth(data: any, expire = 0) {
|
||||
const authKey = `auth:${getRandomChars(32)}`;
|
||||
|
||||
await redis.client.set(authKey, data);
|
||||
const redis = getClient();
|
||||
|
||||
await redis.set(authKey, data);
|
||||
|
||||
if (expire) {
|
||||
await redis.client.expire(authKey, expire);
|
||||
await redis.expire(authKey, expire);
|
||||
}
|
||||
|
||||
return createSecureToken({ authKey }, secret());
|
||||
|
@ -68,6 +68,10 @@ function getDateSQL(field: string, unit: string, timezone?: string) {
|
||||
return `toDateTime(date_trunc('${unit}', ${field}))`;
|
||||
}
|
||||
|
||||
function getSearchSQL(column: string, param: string = 'search'): string {
|
||||
return `and positionCaseInsensitive(${column}, {${param}:String}) > 0`;
|
||||
}
|
||||
|
||||
function mapFilter(column: string, operator: string, name: string, type: string = 'String') {
|
||||
const value = `{${name}:${type}}`;
|
||||
|
||||
@ -229,6 +233,7 @@ export default {
|
||||
connect,
|
||||
getDateStringSQL,
|
||||
getDateSQL,
|
||||
getSearchSQL,
|
||||
getFilterQuery,
|
||||
getUTCString,
|
||||
parseFilters,
|
||||
|
@ -1,4 +1,3 @@
|
||||
import moment from 'moment-timezone';
|
||||
import {
|
||||
addMinutes,
|
||||
addHours,
|
||||
@ -105,8 +104,17 @@ const DATE_FUNCTIONS = {
|
||||
},
|
||||
};
|
||||
|
||||
export function isValidTimezone(timezone: string) {
|
||||
try {
|
||||
Intl.DateTimeFormat(undefined, { timeZone: timezone });
|
||||
return true;
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function getTimezone() {
|
||||
return moment.tz.guess();
|
||||
return Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
}
|
||||
|
||||
export function parseDateValue(value: string) {
|
||||
|
@ -67,6 +67,14 @@ function getRegionCode(country: string, region: string) {
|
||||
return region.includes('-') ? region : `${country}-${region}`;
|
||||
}
|
||||
|
||||
function safeDecodeCfHeader(s: string | undefined | null): string | undefined | null {
|
||||
if (s === undefined || s === null) {
|
||||
return s;
|
||||
}
|
||||
|
||||
return Buffer.from(s, 'latin1').toString('utf-8');
|
||||
}
|
||||
|
||||
export async function getLocation(ip: string, req: NextApiRequestCollect) {
|
||||
// Ignore local ips
|
||||
if (await isLocalhost(ip)) {
|
||||
@ -75,9 +83,9 @@ export async function getLocation(ip: string, req: NextApiRequestCollect) {
|
||||
|
||||
// Cloudflare headers
|
||||
if (req.headers['cf-ipcountry']) {
|
||||
const country = safeDecodeURIComponent(req.headers['cf-ipcountry']);
|
||||
const subdivision1 = safeDecodeURIComponent(req.headers['cf-region-code']);
|
||||
const city = safeDecodeURIComponent(req.headers['cf-ipcity']);
|
||||
const country = safeDecodeCfHeader(req.headers['cf-ipcountry']);
|
||||
const subdivision1 = safeDecodeCfHeader(req.headers['cf-region-code']);
|
||||
const city = safeDecodeCfHeader(req.headers['cf-ipcity']);
|
||||
|
||||
return {
|
||||
country,
|
||||
|
@ -1,12 +1,14 @@
|
||||
import { getWebsiteSession, getWebsite } from 'queries';
|
||||
import { Website, Session } from '@prisma/client';
|
||||
import redis from '@umami/redis-client';
|
||||
import { getClient, redisEnabled } from '@umami/redis-client';
|
||||
|
||||
export async function fetchWebsite(websiteId: string): Promise<Website> {
|
||||
let website = null;
|
||||
|
||||
if (redis.enabled) {
|
||||
website = await redis.client.fetch(`website:${websiteId}`, () => getWebsite(websiteId), 86400);
|
||||
if (redisEnabled) {
|
||||
const redis = getClient();
|
||||
|
||||
website = await redis.fetch(`website:${websiteId}`, () => getWebsite(websiteId), 86400);
|
||||
} else {
|
||||
website = await getWebsite(websiteId);
|
||||
}
|
||||
@ -21,8 +23,10 @@ export async function fetchWebsite(websiteId: string): Promise<Website> {
|
||||
export async function fetchSession(websiteId: string, sessionId: string): Promise<Session> {
|
||||
let session = null;
|
||||
|
||||
if (redis.enabled) {
|
||||
session = await redis.client.fetch(
|
||||
if (redisEnabled) {
|
||||
const redis = getClient();
|
||||
|
||||
session = await redis.fetch(
|
||||
`session:${sessionId}`,
|
||||
() => getWebsiteSession(websiteId, sessionId),
|
||||
86400,
|
||||
|
@ -1,6 +1,6 @@
|
||||
import cors from 'cors';
|
||||
import debug from 'debug';
|
||||
import redis from '@umami/redis-client';
|
||||
import { getClient, redisEnabled } from '@umami/redis-client';
|
||||
import { getAuthToken, parseShareToken } from 'lib/auth';
|
||||
import { ROLES } from 'lib/constants';
|
||||
import { secret } from 'lib/crypto';
|
||||
@ -54,8 +54,10 @@ export const useAuth = createMiddleware(async (req, res, next) => {
|
||||
|
||||
if (userId) {
|
||||
user = await getUser(userId);
|
||||
} else if (redis.enabled && authKey) {
|
||||
const key = await redis.client.get(authKey);
|
||||
} else if (redisEnabled && authKey) {
|
||||
const redis = getClient();
|
||||
|
||||
const key = await redis.get(authKey);
|
||||
|
||||
if (key?.userId) {
|
||||
user = await getUser(key.userId);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import debug from 'debug';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import prisma from '@umami/prisma-client';
|
||||
import moment from 'moment-timezone';
|
||||
import { formatInTimeZone } from 'date-fns-tz';
|
||||
import { MYSQL, POSTGRESQL, getDatabaseType } from 'lib/db';
|
||||
import { SESSION_COLUMNS, OPERATORS, DEFAULT_PAGE_SIZE } from './constants';
|
||||
import { fetchWebsite } from './load';
|
||||
@ -75,7 +75,7 @@ function getDateSQL(field: string, unit: string, timezone?: string): string {
|
||||
|
||||
if (db === MYSQL) {
|
||||
if (timezone) {
|
||||
const tz = moment.tz(timezone).format('Z');
|
||||
const tz = formatInTimeZone(new Date(), timezone, 'yyyy-MM-dd HH:mm:ss');
|
||||
return `date_format(convert_tz(${field},'+00:00','${tz}'), '${MYSQL_DATE_FORMATS[unit]}')`;
|
||||
}
|
||||
return `date_format(${field}, '${MYSQL_DATE_FORMATS[unit]}')`;
|
||||
@ -90,7 +90,7 @@ function getDateWeeklySQL(field: string, timezone?: string) {
|
||||
}
|
||||
|
||||
if (db === MYSQL) {
|
||||
const tz = moment.tz(timezone).format('Z');
|
||||
const tz = formatInTimeZone(new Date(), timezone, 'yyyy-MM-dd HH:mm:ss');
|
||||
return `date_format(convert_tz(${field},'+00:00','${tz}'), '%w:%H')`;
|
||||
}
|
||||
}
|
||||
@ -119,11 +119,11 @@ function getTimestampDiffSQL(field1: string, field2: string): string {
|
||||
}
|
||||
}
|
||||
|
||||
function getSearchSQL(column: string): string {
|
||||
function getSearchSQL(column: string, param: string = 'search'): string {
|
||||
const db = getDatabaseType();
|
||||
const like = db === POSTGRESQL ? 'ilike' : 'like';
|
||||
|
||||
return `and ${column} ${like} {{search}}`;
|
||||
return `and ${column} ${like} {{${param}}`;
|
||||
}
|
||||
|
||||
function mapFilter(column: string, operator: string, name: string, type: string = '') {
|
||||
|
@ -88,5 +88,5 @@ export async function getSession(req: NextApiRequestCollect): Promise<SessionDat
|
||||
}
|
||||
}
|
||||
|
||||
return { ...session, visitId: visitId };
|
||||
return { ...session, visitId };
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import moment from 'moment-timezone';
|
||||
import * as yup from 'yup';
|
||||
import { isValidTimezone } from 'lib/date';
|
||||
import { UNIT_TYPES } from './constants';
|
||||
|
||||
export const TimezoneTest = yup
|
||||
@ -8,7 +8,7 @@ export const TimezoneTest = yup
|
||||
.test(
|
||||
'timezone',
|
||||
() => `Invalid timezone`,
|
||||
value => moment.tz.zone(value) !== null,
|
||||
value => isValidTimezone(value),
|
||||
);
|
||||
|
||||
export const UnitTypeTest = yup.string().test(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import redis from '@umami/redis-client';
|
||||
import { redisEnabled } from '@umami/redis-client';
|
||||
import { saveAuth } from 'lib/auth';
|
||||
import { secret } from 'lib/crypto';
|
||||
import { useValidate } from 'lib/middleware';
|
||||
@ -49,7 +49,7 @@ export default async (
|
||||
const user = await getUserByUsername(username, { includePassword: true });
|
||||
|
||||
if (user && checkPassword(password, user.password)) {
|
||||
if (redis.enabled) {
|
||||
if (redisEnabled) {
|
||||
const token = await saveAuth({ userId: user.id });
|
||||
|
||||
return ok(res, { token, user });
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { methodNotAllowed, ok } from 'next-basics';
|
||||
import redis from '@umami/redis-client';
|
||||
import { getClient, redisEnabled } from '@umami/redis-client';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { getAuthToken } from 'lib/auth';
|
||||
import { NextApiRequest, NextApiResponse } from 'next';
|
||||
@ -8,8 +8,10 @@ export default async (req: NextApiRequest, res: NextApiResponse) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
if (req.method === 'POST') {
|
||||
if (redis.enabled) {
|
||||
await redis.client.del(getAuthToken(req));
|
||||
if (redisEnabled) {
|
||||
const redis = getClient();
|
||||
|
||||
await redis.del(getAuthToken(req));
|
||||
}
|
||||
|
||||
return ok(res);
|
||||
|
@ -2,13 +2,13 @@ import { NextApiRequestAuth } from 'lib/types';
|
||||
import { useAuth } from 'lib/middleware';
|
||||
import { NextApiResponse } from 'next';
|
||||
import { badRequest, ok } from 'next-basics';
|
||||
import redis from '@umami/redis-client';
|
||||
import { redisEnabled } from '@umami/redis-client';
|
||||
import { saveAuth } from 'lib/auth';
|
||||
|
||||
export default async (req: NextApiRequestAuth, res: NextApiResponse) => {
|
||||
await useAuth(req, res);
|
||||
|
||||
if (redis.enabled && req.auth.user) {
|
||||
if (redisEnabled && req.auth.user) {
|
||||
const token = await saveAuth({ userId: req.auth.user.id }, 86400);
|
||||
|
||||
return ok(res, { user: req.auth.user, token });
|
||||
|
@ -31,7 +31,10 @@ const schema = {
|
||||
.of(
|
||||
yup.object().shape({
|
||||
type: yup.string().required(),
|
||||
value: yup.string().required(),
|
||||
value: yup
|
||||
.string()
|
||||
.matches(/^[a-zA-Z0-9/*-_]+$/, 'Invalid URL pattern')
|
||||
.required(),
|
||||
}),
|
||||
)
|
||||
.min(2)
|
||||
|
@ -102,6 +102,11 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
|
||||
await useSession(req, res);
|
||||
|
||||
const session = req.session;
|
||||
|
||||
if (!session?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const iat = Math.floor(new Date().getTime() / 1000);
|
||||
|
||||
// expire visitId after 30 minutes
|
||||
|
@ -49,13 +49,7 @@ export default async (req: NextApiRequestQueryBody<ValuesRequestQuery>, res: Nex
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const values = await getValues(
|
||||
websiteId,
|
||||
FILTER_COLUMNS[type as string],
|
||||
startDate,
|
||||
endDate,
|
||||
search,
|
||||
);
|
||||
const values = await getValues(websiteId, FILTER_COLUMNS[type], startDate, endDate, search);
|
||||
|
||||
return ok(
|
||||
res,
|
||||
|
@ -19,10 +19,25 @@ async function relationalQuery(
|
||||
search: string,
|
||||
) {
|
||||
const { rawQuery, getSearchSQL } = prisma;
|
||||
const params = {};
|
||||
let searchQuery = '';
|
||||
|
||||
if (search) {
|
||||
searchQuery = getSearchSQL(column);
|
||||
if (decodeURIComponent(search).includes(',')) {
|
||||
searchQuery = `AND (${decodeURIComponent(search)
|
||||
.split(',')
|
||||
.slice(0, 5)
|
||||
.map((value: string, index: number) => {
|
||||
const key = `search${index}`;
|
||||
|
||||
params[key] = value;
|
||||
|
||||
return getSearchSQL(column, key).replace('and ', '');
|
||||
})
|
||||
.join(' OR ')})`;
|
||||
} else {
|
||||
searchQuery = getSearchSQL(column);
|
||||
}
|
||||
}
|
||||
|
||||
return rawQuery(
|
||||
@ -43,6 +58,7 @@ async function relationalQuery(
|
||||
startDate,
|
||||
endDate,
|
||||
search: `%${search}%`,
|
||||
...params,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -54,13 +70,32 @@ async function clickhouseQuery(
|
||||
endDate: Date,
|
||||
search: string,
|
||||
) {
|
||||
const { rawQuery } = clickhouse;
|
||||
const { rawQuery, getSearchSQL } = clickhouse;
|
||||
const params = {};
|
||||
let searchQuery = '';
|
||||
|
||||
if (search) {
|
||||
searchQuery = `and positionCaseInsensitive(${column}, {search:String}) > 0`;
|
||||
}
|
||||
|
||||
if (search) {
|
||||
if (decodeURIComponent(search).includes(',')) {
|
||||
searchQuery = `AND (${decodeURIComponent(search)
|
||||
.split(',')
|
||||
.slice(0, 5)
|
||||
.map((value: string, index: number) => {
|
||||
const key = `search${index}`;
|
||||
|
||||
params[key] = value;
|
||||
|
||||
return getSearchSQL(column, key).replace('and ', '');
|
||||
})
|
||||
.join(' OR ')})`;
|
||||
} else {
|
||||
searchQuery = getSearchSQL(column);
|
||||
}
|
||||
}
|
||||
|
||||
return rawQuery(
|
||||
`
|
||||
select ${column} as value, count(*)
|
||||
@ -77,6 +112,7 @@ async function clickhouseQuery(
|
||||
startDate,
|
||||
endDate,
|
||||
search,
|
||||
...params,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ async function clickhouseQuery(websiteId: string) {
|
||||
select
|
||||
min(created_at) as mindate,
|
||||
max(created_at) as maxdate
|
||||
from website_event
|
||||
from website_event_stats_hourly
|
||||
where website_id = {websiteId:UUID}
|
||||
and created_at >= {startDate:DateTime64}
|
||||
`,
|
||||
|
@ -70,9 +70,16 @@ async function relationalQuery(
|
||||
(pv, cv, i) => {
|
||||
const levelNumber = i + 1;
|
||||
const startSum = i > 0 ? 'union ' : '';
|
||||
const operator = cv.type === 'url' && cv.value.endsWith('*') ? 'like' : '=';
|
||||
const column = cv.type === 'url' ? 'url_path' : 'event_name';
|
||||
const paramValue = cv.value.endsWith('*') ? cv.value.replace('*', '%') : cv.value;
|
||||
const isURL = cv.type === 'url';
|
||||
const column = isURL ? 'url_path' : 'event_name';
|
||||
|
||||
let operator = '=';
|
||||
let paramValue = cv.value;
|
||||
|
||||
if (cv.value.startsWith('*') || cv.value.endsWith('*')) {
|
||||
operator = 'like';
|
||||
paramValue = cv.value.replace(/^\*|\*$/g, '%');
|
||||
}
|
||||
|
||||
if (levelNumber === 1) {
|
||||
pv.levelOneQuery = `
|
||||
@ -167,9 +174,16 @@ async function clickhouseQuery(
|
||||
const levelNumber = i + 1;
|
||||
const startSum = i > 0 ? 'union all ' : '';
|
||||
const startFilter = i > 0 ? 'or' : '';
|
||||
const operator = cv.type === 'url' && cv.value.endsWith('*') ? 'like' : '=';
|
||||
const column = cv.type === 'url' ? 'url_path' : 'event_name';
|
||||
const paramValue = cv.value.endsWith('*') ? cv.value.replace('*', '%') : cv.value;
|
||||
const isURL = cv.type === 'url';
|
||||
const column = isURL ? 'url_path' : 'event_name';
|
||||
|
||||
let operator = '=';
|
||||
let paramValue = cv.value;
|
||||
|
||||
if (cv.value.startsWith('*') || cv.value.endsWith('*')) {
|
||||
operator = 'like';
|
||||
paramValue = cv.value.replace(/^\*|\*$/g, '%');
|
||||
}
|
||||
|
||||
if (levelNumber === 1) {
|
||||
pv.levelOneQuery = `\n
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Prisma, Website } from '@prisma/client';
|
||||
import redis from '@umami/redis-client';
|
||||
import { getClient } from '@umami/redis-client';
|
||||
import prisma from 'lib/prisma';
|
||||
import { PageResult, PageParams } from 'lib/types';
|
||||
import WebsiteFindManyArgs = Prisma.WebsiteFindManyArgs;
|
||||
@ -21,6 +21,7 @@ export async function getSharedWebsite(shareId: string) {
|
||||
return findWebsite({
|
||||
where: {
|
||||
shareId,
|
||||
deletedAt: null,
|
||||
},
|
||||
});
|
||||
}
|
||||
@ -181,7 +182,9 @@ export async function resetWebsite(
|
||||
}),
|
||||
]).then(async data => {
|
||||
if (cloudMode) {
|
||||
await redis.client.set(`website:${websiteId}`, data[3]);
|
||||
const redis = getClient();
|
||||
|
||||
await redis.set(`website:${websiteId}`, data[3]);
|
||||
}
|
||||
|
||||
return data;
|
||||
@ -224,7 +227,9 @@ export async function deleteWebsite(
|
||||
}),
|
||||
]).then(async data => {
|
||||
if (cloudMode) {
|
||||
await redis.client.del(`website:${websiteId}`);
|
||||
const redis = getClient();
|
||||
|
||||
await redis.del(`website:${websiteId}`);
|
||||
}
|
||||
|
||||
return data;
|
||||
|
@ -54,7 +54,7 @@
|
||||
const parseURL = url => {
|
||||
try {
|
||||
// use location.origin as the base to handle cases where the url is a relative path
|
||||
const { pathname, search, hash } = new URL(url, origin);
|
||||
const { pathname, search, hash } = new URL(url, location.href);
|
||||
url = pathname + search + hash;
|
||||
} catch (e) {
|
||||
/* empty */
|
||||
|
492
yarn.lock
492
yarn.lock
@ -1584,6 +1584,13 @@
|
||||
resolved "https://registry.yarnpkg.com/@dicebear/thumbs/-/thumbs-9.2.2.tgz#234814c889509682992bd3f93daaa960cb5326a2"
|
||||
integrity sha512-FkPLDNu7n5kThLSk7lR/0cz/NkUqgGdZGfLZv6fLkGNGtv6W+e2vZaO7HCXVwIgJ+II+kImN41zVIZ6Jlll7pQ==
|
||||
|
||||
"@emnapi/runtime@^1.2.0":
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.3.1.tgz#0fcaa575afc31f455fd33534c19381cfce6c6f60"
|
||||
integrity sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==
|
||||
dependencies:
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@esbuild/android-arm64@0.17.19":
|
||||
version "0.17.19"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz#bafb75234a5d3d1b690e7c2956a599345e84a2fd"
|
||||
@ -1929,17 +1936,118 @@
|
||||
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3"
|
||||
integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==
|
||||
|
||||
"@isaacs/cliui@^8.0.2":
|
||||
version "8.0.2"
|
||||
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
|
||||
integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==
|
||||
"@img/sharp-darwin-arm64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz#ef5b5a07862805f1e8145a377c8ba6e98813ca08"
|
||||
integrity sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-darwin-arm64" "1.0.4"
|
||||
|
||||
"@img/sharp-darwin-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz#e03d3451cd9e664faa72948cc70a403ea4063d61"
|
||||
integrity sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-darwin-x64" "1.0.4"
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz#447c5026700c01a993c7804eb8af5f6e9868c07f"
|
||||
integrity sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==
|
||||
|
||||
"@img/sharp-libvips-darwin-x64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz#e0456f8f7c623f9dbfbdc77383caa72281d86062"
|
||||
integrity sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==
|
||||
|
||||
"@img/sharp-libvips-linux-arm64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz#979b1c66c9a91f7ff2893556ef267f90ebe51704"
|
||||
integrity sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==
|
||||
|
||||
"@img/sharp-libvips-linux-arm@1.0.5":
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz#99f922d4e15216ec205dcb6891b721bfd2884197"
|
||||
integrity sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==
|
||||
|
||||
"@img/sharp-libvips-linux-s390x@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz#f8a5eb1f374a082f72b3f45e2fb25b8118a8a5ce"
|
||||
integrity sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==
|
||||
|
||||
"@img/sharp-libvips-linux-x64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz#d4c4619cdd157774906e15770ee119931c7ef5e0"
|
||||
integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz#166778da0f48dd2bded1fa3033cee6b588f0d5d5"
|
||||
integrity sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-x64@1.0.4":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz#93794e4d7720b077fcad3e02982f2f1c246751ff"
|
||||
integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==
|
||||
|
||||
"@img/sharp-linux-arm64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz#edb0697e7a8279c9fc829a60fc35644c4839bb22"
|
||||
integrity sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-arm64" "1.0.4"
|
||||
|
||||
"@img/sharp-linux-arm@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz#422c1a352e7b5832842577dc51602bcd5b6f5eff"
|
||||
integrity sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-arm" "1.0.5"
|
||||
|
||||
"@img/sharp-linux-s390x@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz#f5c077926b48e97e4a04d004dfaf175972059667"
|
||||
integrity sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-s390x" "1.0.4"
|
||||
|
||||
"@img/sharp-linux-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz#d806e0afd71ae6775cc87f0da8f2d03a7c2209cb"
|
||||
integrity sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linux-x64" "1.0.4"
|
||||
|
||||
"@img/sharp-linuxmusl-arm64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz#252975b915894fb315af5deea174651e208d3d6b"
|
||||
integrity sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linuxmusl-arm64" "1.0.4"
|
||||
|
||||
"@img/sharp-linuxmusl-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz#3f4609ac5d8ef8ec7dadee80b560961a60fd4f48"
|
||||
integrity sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==
|
||||
optionalDependencies:
|
||||
"@img/sharp-libvips-linuxmusl-x64" "1.0.4"
|
||||
|
||||
"@img/sharp-wasm32@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz#6f44f3283069d935bb5ca5813153572f3e6f61a1"
|
||||
integrity sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==
|
||||
dependencies:
|
||||
string-width "^5.1.2"
|
||||
string-width-cjs "npm:string-width@^4.2.0"
|
||||
strip-ansi "^7.0.1"
|
||||
strip-ansi-cjs "npm:strip-ansi@^6.0.1"
|
||||
wrap-ansi "^8.1.0"
|
||||
wrap-ansi-cjs "npm:wrap-ansi@^7.0.0"
|
||||
"@emnapi/runtime" "^1.2.0"
|
||||
|
||||
"@img/sharp-win32-ia32@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz#1a0c839a40c5351e9885628c85f2e5dfd02b52a9"
|
||||
integrity sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==
|
||||
|
||||
"@img/sharp-win32-x64@0.33.5":
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz#56f00962ff0c4e0eb93d34a047d29fa995e3e342"
|
||||
integrity sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==
|
||||
|
||||
"@istanbuljs/load-nyc-config@^1.0.0":
|
||||
version "1.1.0"
|
||||
@ -2215,10 +2323,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@netlify/plugin-nextjs/-/plugin-nextjs-5.8.1.tgz#9da15bb4a13c5644e9b58b968c7da51939206ee4"
|
||||
integrity sha512-WB1N0FslhWZ1yAVYTcB6CcFrFOUSQ0O2LfavYZrbAypeNxu2I+oO+cgmhfDgZ8Eoq1g4EMeoIGMkNoZ4ogZTsg==
|
||||
|
||||
"@next/env@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-14.2.10.tgz#1d3178340028ced2d679f84140877db4f420333c"
|
||||
integrity sha512-dZIu93Bf5LUtluBXIv4woQw2cZVZ2DJTjax5/5DOs3lzEOeKLy7GxRSr4caK9/SCPdaW6bCgpye6+n4Dh9oJPw==
|
||||
"@next/env@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.0.4.tgz#97da0fe3bae2f2b2968c4c925d7936660f5b3836"
|
||||
integrity sha512-WNRvtgnRVDD4oM8gbUcRc27IAhaL4eXQ/2ovGbgLnPGUvdyDr8UdXP4Q/IBDdAdojnD2eScryIDirv0YUCjUVw==
|
||||
|
||||
"@next/eslint-plugin-next@14.2.18":
|
||||
version "14.2.18"
|
||||
@ -2227,50 +2335,45 @@
|
||||
dependencies:
|
||||
glob "10.3.10"
|
||||
|
||||
"@next/swc-darwin-arm64@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.10.tgz#49d10ca4086fbd59ee68e204f75d7136eda2aa80"
|
||||
integrity sha512-V3z10NV+cvMAfxQUMhKgfQnPbjw+Ew3cnr64b0lr8MDiBJs3eLnM6RpGC46nhfMZsiXgQngCJKWGTC/yDcgrDQ==
|
||||
"@next/swc-darwin-arm64@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.4.tgz#66087f397564d6ece4c5493536d30bc2b158a80e"
|
||||
integrity sha512-QecQXPD0yRHxSXWL5Ff80nD+A56sUXZG9koUsjWJwA2Z0ZgVQfuy7gd0/otjxoOovPVHR2eVEvPMHbtZP+pf9w==
|
||||
|
||||
"@next/swc-darwin-x64@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.10.tgz#0ebeae3afb8eac433882b79543295ab83624a1a8"
|
||||
integrity sha512-Y0TC+FXbFUQ2MQgimJ/7Ina2mXIKhE7F+GUe1SgnzRmwFY3hX2z8nyVCxE82I2RicspdkZnSWMn4oTjIKz4uzA==
|
||||
"@next/swc-darwin-x64@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.4.tgz#6eb098e183dfed72d8f3c4b281a323ad17d72446"
|
||||
integrity sha512-pb7Bye3y1Og3PlCtnz2oO4z+/b3pH2/HSYkLbL0hbVuTGil7fPen8/3pyyLjdiTLcFJ+ymeU3bck5hd4IPFFCA==
|
||||
|
||||
"@next/swc-linux-arm64-gnu@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.10.tgz#7e602916d2fb55a3c532f74bed926a0137c16f20"
|
||||
integrity sha512-ZfQ7yOy5zyskSj9rFpa0Yd7gkrBnJTkYVSya95hX3zeBG9E55Z6OTNPn1j2BTFWvOVVj65C3T+qsjOyVI9DQpA==
|
||||
"@next/swc-linux-arm64-gnu@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.4.tgz#3c082ad1a4c8060a5c56127fdefb82a149d3b94e"
|
||||
integrity sha512-12oSaBFjGpB227VHzoXF3gJoK2SlVGmFJMaBJSu5rbpaoT5OjP5OuCLuR9/jnyBF1BAWMs/boa6mLMoJPRriMA==
|
||||
|
||||
"@next/swc-linux-arm64-musl@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.10.tgz#6b143f628ccee490b527562e934f8de578d4be47"
|
||||
integrity sha512-n2i5o3y2jpBfXFRxDREr342BGIQCJbdAUi/K4q6Env3aSx8erM9VuKXHw5KNROK9ejFSPf0LhoSkU/ZiNdacpQ==
|
||||
"@next/swc-linux-arm64-musl@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.4.tgz#c4e18c89ea4dab6b150b889643ec19896aebc1eb"
|
||||
integrity sha512-QARO88fR/a+wg+OFC3dGytJVVviiYFEyjc/Zzkjn/HevUuJ7qGUUAUYy5PGVWY1YgTzeRYz78akQrVQ8r+sMjw==
|
||||
|
||||
"@next/swc-linux-x64-gnu@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.10.tgz#086f2f16a0678890a1eb46518c4dda381b046082"
|
||||
integrity sha512-GXvajAWh2woTT0GKEDlkVhFNxhJS/XdDmrVHrPOA83pLzlGPQnixqxD8u3bBB9oATBKB//5e4vpACnx5Vaxdqg==
|
||||
"@next/swc-linux-x64-gnu@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.4.tgz#f81c3952a60f3075b48e0b5a862f4deecd550c2d"
|
||||
integrity sha512-Z50b0gvYiUU1vLzfAMiChV8Y+6u/T2mdfpXPHraqpypP7yIT2UV9YBBhcwYkxujmCvGEcRTVWOj3EP7XW/wUnw==
|
||||
|
||||
"@next/swc-linux-x64-musl@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.10.tgz#1befef10ed8dbcc5047b5d637a25ae3c30a0bfc3"
|
||||
integrity sha512-opFFN5B0SnO+HTz4Wq4HaylXGFV+iHrVxd3YvREUX9K+xfc4ePbRrxqOuPOFjtSuiVouwe6uLeDtabjEIbkmDA==
|
||||
"@next/swc-linux-x64-musl@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.4.tgz#f14c9730599985538d4d01d6da825b4e41fea0c1"
|
||||
integrity sha512-7H9C4FAsrTAbA/ENzvFWsVytqRYhaJYKa2B3fyQcv96TkOGVMcvyS6s+sj4jZlacxxTcn7ygaMXUPkEk7b78zw==
|
||||
|
||||
"@next/swc-win32-arm64-msvc@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.10.tgz#731f52c3ae3c56a26cf21d474b11ae1529531209"
|
||||
integrity sha512-9NUzZuR8WiXTvv+EiU/MXdcQ1XUvFixbLIMNQiVHuzs7ZIFrJDLJDaOF1KaqttoTujpcxljM/RNAOmw1GhPPQQ==
|
||||
"@next/swc-win32-arm64-msvc@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.4.tgz#14297572feedcd5b14388be8a7ea8c50accb4c96"
|
||||
integrity sha512-Z/v3WV5xRaeWlgJzN9r4PydWD8sXV35ywc28W63i37G2jnUgScA4OOgS8hQdiXLxE3gqfSuHTicUhr7931OXPQ==
|
||||
|
||||
"@next/swc-win32-ia32-msvc@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.10.tgz#32723ef7f04e25be12af357cc72ddfdd42fd1041"
|
||||
integrity sha512-fr3aEbSd1GeW3YUMBkWAu4hcdjZ6g4NBl1uku4gAn661tcxd1bHs1THWYzdsbTRLcCKLjrDZlNp6j2HTfrw+Bg==
|
||||
|
||||
"@next/swc-win32-x64-msvc@14.2.10":
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.10.tgz#ee1d036cb5ec871816f96baee7991035bb242455"
|
||||
integrity sha512-UjeVoRGKNL2zfbcQ6fscmgjBAS/inHBh63mjIlfPg/NG8Yn2ztqylXt5qilYb6hoHIwaU2ogHknHWWmahJjgZQ==
|
||||
"@next/swc-win32-x64-msvc@15.0.4":
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.4.tgz#d25953baffb92721f0fb96c8be71d7efb37a57b7"
|
||||
integrity sha512-NGLchGruagh8lQpDr98bHLyWJXOBSmkEAfK980OiNBa7vNm6PsNoPvzTfstT78WyOeMRQphEQ455rggd7Eo+Dw==
|
||||
|
||||
"@nodelib/fs.scandir@2.1.5":
|
||||
version "2.1.5"
|
||||
@ -2303,51 +2406,51 @@
|
||||
resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33"
|
||||
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==
|
||||
|
||||
"@prisma/client@5.17":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.17.0.tgz#9079947bd749689c2dabfb9ecc70a24ebefb1f43"
|
||||
integrity sha512-N2tnyKayT0Zf7mHjwEyE8iG7FwTmXDHFZ1GnNhQp0pJUObsuel4ZZ1XwfuAYkq5mRIiC/Kot0kt0tGCfLJ70Jw==
|
||||
"@prisma/client@5.22.0":
|
||||
version "5.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.22.0.tgz#da1ca9c133fbefe89e0da781c75e1c59da5f8802"
|
||||
integrity sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==
|
||||
|
||||
"@prisma/debug@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.17.0.tgz#a765105848993984535b6066f8ebc6e6ead26533"
|
||||
integrity sha512-l7+AteR3P8FXiYyo496zkuoiJ5r9jLQEdUuxIxNCN1ud8rdbH3GTxm+f+dCyaSv9l9WY+29L9czaVRXz9mULfg==
|
||||
"@prisma/debug@5.22.0":
|
||||
version "5.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.22.0.tgz#58af56ed7f6f313df9fb1042b6224d3174bbf412"
|
||||
integrity sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==
|
||||
|
||||
"@prisma/engines-version@5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053":
|
||||
version "5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053.tgz#3c7cc1ef3ebc34cbd069e5873b9982f2aabf5acd"
|
||||
integrity sha512-tUuxZZysZDcrk5oaNOdrBnnkoTtmNQPkzINFDjz7eG6vcs9AVDmA/F6K5Plsb2aQc/l5M2EnFqn3htng9FA4hg==
|
||||
"@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2":
|
||||
version "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz#d534dd7235c1ba5a23bacd5b92cc0ca3894c28f4"
|
||||
integrity sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==
|
||||
|
||||
"@prisma/engines@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.17.0.tgz#74dd1aabb22675892760b3cf69a448e3aef4616b"
|
||||
integrity sha512-+r+Nf+JP210Jur+/X8SIPLtz+uW9YA4QO5IXA+KcSOBe/shT47bCcRMTYCbOESw3FFYFTwe7vU6KTWHKPiwvtg==
|
||||
"@prisma/engines@5.22.0":
|
||||
version "5.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.22.0.tgz#28f3f52a2812c990a8b66eb93a0987816a5b6d84"
|
||||
integrity sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==
|
||||
dependencies:
|
||||
"@prisma/debug" "5.17.0"
|
||||
"@prisma/engines-version" "5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053"
|
||||
"@prisma/fetch-engine" "5.17.0"
|
||||
"@prisma/get-platform" "5.17.0"
|
||||
"@prisma/debug" "5.22.0"
|
||||
"@prisma/engines-version" "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2"
|
||||
"@prisma/fetch-engine" "5.22.0"
|
||||
"@prisma/get-platform" "5.22.0"
|
||||
|
||||
"@prisma/extension-read-replicas@^0.3.0":
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/extension-read-replicas/-/extension-read-replicas-0.3.0.tgz#2842a7c928f957c1dd58a6256104797596d43426"
|
||||
integrity sha512-F9+rSmYday6GT2qjhJtkZcBOpLO5LtpvFcMGqrBDHf+78LEdSuxfFjOxYlNuqk4B+th62yxpbhfpmB9/Mca14Q==
|
||||
|
||||
"@prisma/fetch-engine@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.17.0.tgz#f718dc7426411d1ebeeee53e2d0d38652387f87c"
|
||||
integrity sha512-ESxiOaHuC488ilLPnrv/tM2KrPhQB5TRris/IeIV4ZvUuKeaicCl4Xj/JCQeG9IlxqOgf1cCg5h5vAzlewN91Q==
|
||||
"@prisma/fetch-engine@5.22.0":
|
||||
version "5.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz#4fb691b483a450c5548aac2f837b267dd50ef52e"
|
||||
integrity sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==
|
||||
dependencies:
|
||||
"@prisma/debug" "5.17.0"
|
||||
"@prisma/engines-version" "5.17.0-31.393aa359c9ad4a4bb28630fb5613f9c281cde053"
|
||||
"@prisma/get-platform" "5.17.0"
|
||||
"@prisma/debug" "5.22.0"
|
||||
"@prisma/engines-version" "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2"
|
||||
"@prisma/get-platform" "5.22.0"
|
||||
|
||||
"@prisma/get-platform@5.17.0":
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.17.0.tgz#89fdcae2adddebbbf0e7bd0474a6c49d6023519b"
|
||||
integrity sha512-UlDgbRozCP1rfJ5Tlkf3Cnftb6srGrEQ4Nm3og+1Se2gWmCZ0hmPIi+tQikGDUVLlvOWx3Gyi9LzgRP+HTXV9w==
|
||||
"@prisma/get-platform@5.22.0":
|
||||
version "5.22.0"
|
||||
resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.22.0.tgz#fc675bc9d12614ca2dade0506c9c4a77e7dddacd"
|
||||
integrity sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==
|
||||
dependencies:
|
||||
"@prisma/debug" "5.17.0"
|
||||
"@prisma/debug" "5.22.0"
|
||||
|
||||
"@react-spring/animated@~9.7.5":
|
||||
version "9.7.5"
|
||||
@ -2648,17 +2751,16 @@
|
||||
"@svgr/plugin-jsx" "8.1.0"
|
||||
"@svgr/plugin-svgo" "8.1.0"
|
||||
|
||||
"@swc/counter@^0.1.3":
|
||||
"@swc/counter@0.1.3":
|
||||
version "0.1.3"
|
||||
resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
|
||||
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
|
||||
|
||||
"@swc/helpers@0.5.5":
|
||||
version "0.5.5"
|
||||
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.5.tgz#12689df71bfc9b21c4f4ca00ae55f2f16c8b77c0"
|
||||
integrity sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==
|
||||
"@swc/helpers@0.5.13":
|
||||
version "0.5.13"
|
||||
resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.13.tgz#33e63ff3cd0cade557672bd7888a39ce7d115a8c"
|
||||
integrity sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==
|
||||
dependencies:
|
||||
"@swc/counter" "^0.1.3"
|
||||
tslib "^2.4.0"
|
||||
|
||||
"@tanstack/query-core@5.60.6":
|
||||
@ -3224,10 +3326,10 @@
|
||||
chalk "^4.1.2"
|
||||
debug "^4.3.4"
|
||||
|
||||
"@umami/redis-client@^0.21.0":
|
||||
version "0.21.0"
|
||||
resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.21.0.tgz#96426b28860b8b06fae8825fc2f2d9575b64e863"
|
||||
integrity sha512-PpdJunvT4sAsVWIeEl+cHU6iSV2r/Df9dof2gdUwSigfD88ACsVs1/BvlWERxk/T93rTgVJWSpLvdw/oMYvkcw==
|
||||
"@umami/redis-client@^0.24.0":
|
||||
version "0.24.0"
|
||||
resolved "https://registry.yarnpkg.com/@umami/redis-client/-/redis-client-0.24.0.tgz#8af489250396be76bc0906766343620589774c4b"
|
||||
integrity sha512-yUZmC87H5QZKNA6jD9k/7d8WDaXQTDROlpyK7S+V2csD96eAnMNi7JsWAVWx9T/584QKD8DsSIy87PTWq1HNPw==
|
||||
dependencies:
|
||||
debug "^4.3.4"
|
||||
redis "^4.5.1"
|
||||
@ -4131,11 +4233,27 @@ color-name@1.1.3:
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
|
||||
|
||||
color-name@~1.1.4:
|
||||
color-name@^1.0.0, color-name@~1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||
|
||||
color-string@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
|
||||
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
|
||||
dependencies:
|
||||
color-name "^1.0.0"
|
||||
simple-swizzle "^0.2.2"
|
||||
|
||||
color@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
|
||||
integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
|
||||
dependencies:
|
||||
color-convert "^2.0.1"
|
||||
color-string "^1.9.0"
|
||||
|
||||
colord@^2.9.1, colord@^2.9.2, colord@^2.9.3:
|
||||
version "2.9.3"
|
||||
resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43"
|
||||
@ -4782,6 +4900,11 @@ detect-indent@^6.0.0:
|
||||
resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6"
|
||||
integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==
|
||||
|
||||
detect-libc@^2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700"
|
||||
integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==
|
||||
|
||||
detect-newline@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
|
||||
@ -5793,7 +5916,7 @@ fs.realpath@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
|
||||
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
|
||||
|
||||
fsevents@^2.3.2, fsevents@~2.3.2:
|
||||
fsevents@2.3.3, fsevents@^2.3.2, fsevents@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
|
||||
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
|
||||
@ -6048,7 +6171,7 @@ gopd@^1.0.1:
|
||||
dependencies:
|
||||
get-intrinsic "^1.1.3"
|
||||
|
||||
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
|
||||
graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
|
||||
version "4.2.11"
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
|
||||
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
|
||||
@ -6327,6 +6450,11 @@ is-arrayish@^0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
|
||||
integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
|
||||
|
||||
is-arrayish@^0.3.1:
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
|
||||
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
|
||||
|
||||
is-async-function@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646"
|
||||
@ -6689,12 +6817,12 @@ iterator.prototype@^1.1.3:
|
||||
reflect.getprototypeof "^1.0.4"
|
||||
set-function-name "^2.0.1"
|
||||
|
||||
jackspeak@^2.3.5:
|
||||
version "2.3.6"
|
||||
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
|
||||
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
|
||||
jackspeak@2.1.1, jackspeak@^2.3.5:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.1.1.tgz#2a42db4cfbb7e55433c28b6f75d8b796af9669cd"
|
||||
integrity sha512-juf9stUEwUaILepraGOWIJTLwg48bUnBmRqd2ln2Os1sW987zeoj/hzhbvRB95oMuS2ZTpjULmdwHNX4rzZIZw==
|
||||
dependencies:
|
||||
"@isaacs/cliui" "^8.0.2"
|
||||
cliui "^8.0.1"
|
||||
optionalDependencies:
|
||||
"@pkgjs/parseargs" "^0.11.0"
|
||||
|
||||
@ -7515,7 +7643,7 @@ log-update@^5.0.1:
|
||||
strip-ansi "^7.0.1"
|
||||
wrap-ansi "^8.0.1"
|
||||
|
||||
loose-envify@^1.1.0, loose-envify@^1.4.0:
|
||||
loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
@ -7818,18 +7946,6 @@ mmdb-lib@2.1.1:
|
||||
resolved "https://registry.yarnpkg.com/mmdb-lib/-/mmdb-lib-2.1.1.tgz#c0d0bd35dc1fca41f0ebd043e43227ab04eb1792"
|
||||
integrity sha512-yx8H/1H5AfnufiLnzzPqPf4yr/dKU9IFT1rPVwSkrKWHsQEeVVd6+X+L0nUbXhlEFTu3y/7hu38CFmEVgzvyeg==
|
||||
|
||||
moment-timezone@^0.5.35:
|
||||
version "0.5.46"
|
||||
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.46.tgz#a21aa6392b3c6b3ed916cd5e95858a28d893704a"
|
||||
integrity sha512-ZXm9b36esbe7OmdABqIWJuBBiLLwAjrN7CE+7sYdCCx82Nabt1wHDj8TVseS59QIlfFPbOoiBPm6ca9BioG4hw==
|
||||
dependencies:
|
||||
moment "^2.29.4"
|
||||
|
||||
moment@^2.29.4:
|
||||
version "2.30.1"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae"
|
||||
integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
@ -7864,28 +7980,28 @@ next-basics@^0.39.0:
|
||||
jsonwebtoken "^9.0.0"
|
||||
pure-rand "^6.0.2"
|
||||
|
||||
next@14.2.10:
|
||||
version "14.2.10"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-14.2.10.tgz#331981a4fecb1ae8af1817d4db98fc9687ee1cb6"
|
||||
integrity sha512-sDDExXnh33cY3RkS9JuFEKaS4HmlWmDKP1VJioucCG6z5KuA008DPsDZOzi8UfqEk3Ii+2NCQSJrfbEWtZZfww==
|
||||
next@15.0.4:
|
||||
version "15.0.4"
|
||||
resolved "https://registry.yarnpkg.com/next/-/next-15.0.4.tgz#7ddad7299204f16c132d7e524cf903f1a513588e"
|
||||
integrity sha512-nuy8FH6M1FG0lktGotamQDCXhh5hZ19Vo0ht1AOIQWrYJLP598TIUagKtvJrfJ5AGwB/WmDqkKaKhMpVifvGPA==
|
||||
dependencies:
|
||||
"@next/env" "14.2.10"
|
||||
"@swc/helpers" "0.5.5"
|
||||
"@next/env" "15.0.4"
|
||||
"@swc/counter" "0.1.3"
|
||||
"@swc/helpers" "0.5.13"
|
||||
busboy "1.6.0"
|
||||
caniuse-lite "^1.0.30001579"
|
||||
graceful-fs "^4.2.11"
|
||||
postcss "8.4.31"
|
||||
styled-jsx "5.1.1"
|
||||
styled-jsx "5.1.6"
|
||||
optionalDependencies:
|
||||
"@next/swc-darwin-arm64" "14.2.10"
|
||||
"@next/swc-darwin-x64" "14.2.10"
|
||||
"@next/swc-linux-arm64-gnu" "14.2.10"
|
||||
"@next/swc-linux-arm64-musl" "14.2.10"
|
||||
"@next/swc-linux-x64-gnu" "14.2.10"
|
||||
"@next/swc-linux-x64-musl" "14.2.10"
|
||||
"@next/swc-win32-arm64-msvc" "14.2.10"
|
||||
"@next/swc-win32-ia32-msvc" "14.2.10"
|
||||
"@next/swc-win32-x64-msvc" "14.2.10"
|
||||
"@next/swc-darwin-arm64" "15.0.4"
|
||||
"@next/swc-darwin-x64" "15.0.4"
|
||||
"@next/swc-linux-arm64-gnu" "15.0.4"
|
||||
"@next/swc-linux-arm64-musl" "15.0.4"
|
||||
"@next/swc-linux-x64-gnu" "15.0.4"
|
||||
"@next/swc-linux-x64-musl" "15.0.4"
|
||||
"@next/swc-win32-arm64-msvc" "15.0.4"
|
||||
"@next/swc-win32-x64-msvc" "15.0.4"
|
||||
sharp "^0.33.5"
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.5"
|
||||
@ -8914,12 +9030,14 @@ pretty-format@^29.0.0, pretty-format@^29.7.0:
|
||||
ansi-styles "^5.0.0"
|
||||
react-is "^18.0.0"
|
||||
|
||||
prisma@5.17:
|
||||
version "5.17.0"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.17.0.tgz#267b43921ab94805b010537cffa5ccaf530fa066"
|
||||
integrity sha512-m4UWkN5lBE6yevqeOxEvmepnL5cNPEjzMw2IqDB59AcEV6w7D8vGljDLd1gPFH+W6gUxw9x7/RmN5dCS/WTPxA==
|
||||
prisma@5.22.0:
|
||||
version "5.22.0"
|
||||
resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.22.0.tgz#1f6717ff487cdef5f5799cc1010459920e2e6197"
|
||||
integrity sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==
|
||||
dependencies:
|
||||
"@prisma/engines" "5.17.0"
|
||||
"@prisma/engines" "5.22.0"
|
||||
optionalDependencies:
|
||||
fsevents "2.3.3"
|
||||
|
||||
process@^0.11.10:
|
||||
version "0.11.10"
|
||||
@ -9034,13 +9152,12 @@ react-beautiful-dnd@^13.1.0:
|
||||
redux "^4.0.4"
|
||||
use-memo-one "^1.1.1"
|
||||
|
||||
react-dom@^18.2.0:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
|
||||
integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
|
||||
react-dom@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.0.0.tgz#43446f1f01c65a4cd7f7588083e686a6726cfb57"
|
||||
integrity sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler "^0.23.2"
|
||||
scheduler "^0.25.0"
|
||||
|
||||
react-error-boundary@^4.0.4:
|
||||
version "4.1.2"
|
||||
@ -9122,12 +9239,10 @@ react-window@^1.8.6:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
memoize-one ">=3.1.1 <6"
|
||||
|
||||
react@^18.2.0:
|
||||
version "18.3.1"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
|
||||
integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
react@^19.0.0:
|
||||
version "19.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-19.0.0.tgz#6e1969251b9f108870aa4bff37a0ce9ddfaaabdd"
|
||||
integrity sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==
|
||||
|
||||
read-babelrc-up@^1.1.0:
|
||||
version "1.1.0"
|
||||
@ -9536,12 +9651,10 @@ safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
scheduler@^0.23.2:
|
||||
version "0.23.2"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
|
||||
integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
scheduler@^0.25.0:
|
||||
version "0.25.0"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.25.0.tgz#336cd9768e8cceebf52d3c80e3dcf5de23e7e015"
|
||||
integrity sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==
|
||||
|
||||
schema-utils@*:
|
||||
version "4.2.0"
|
||||
@ -9606,6 +9719,35 @@ set-function-name@^2.0.1, set-function-name@^2.0.2:
|
||||
functions-have-names "^1.2.3"
|
||||
has-property-descriptors "^1.0.2"
|
||||
|
||||
sharp@^0.33.5:
|
||||
version "0.33.5"
|
||||
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.33.5.tgz#13e0e4130cc309d6a9497596715240b2ec0c594e"
|
||||
integrity sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==
|
||||
dependencies:
|
||||
color "^4.2.3"
|
||||
detect-libc "^2.0.3"
|
||||
semver "^7.6.3"
|
||||
optionalDependencies:
|
||||
"@img/sharp-darwin-arm64" "0.33.5"
|
||||
"@img/sharp-darwin-x64" "0.33.5"
|
||||
"@img/sharp-libvips-darwin-arm64" "1.0.4"
|
||||
"@img/sharp-libvips-darwin-x64" "1.0.4"
|
||||
"@img/sharp-libvips-linux-arm" "1.0.5"
|
||||
"@img/sharp-libvips-linux-arm64" "1.0.4"
|
||||
"@img/sharp-libvips-linux-s390x" "1.0.4"
|
||||
"@img/sharp-libvips-linux-x64" "1.0.4"
|
||||
"@img/sharp-libvips-linuxmusl-arm64" "1.0.4"
|
||||
"@img/sharp-libvips-linuxmusl-x64" "1.0.4"
|
||||
"@img/sharp-linux-arm" "0.33.5"
|
||||
"@img/sharp-linux-arm64" "0.33.5"
|
||||
"@img/sharp-linux-s390x" "0.33.5"
|
||||
"@img/sharp-linux-x64" "0.33.5"
|
||||
"@img/sharp-linuxmusl-arm64" "0.33.5"
|
||||
"@img/sharp-linuxmusl-x64" "0.33.5"
|
||||
"@img/sharp-wasm32" "0.33.5"
|
||||
"@img/sharp-win32-ia32" "0.33.5"
|
||||
"@img/sharp-win32-x64" "0.33.5"
|
||||
|
||||
shebang-command@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
|
||||
@ -9655,6 +9797,13 @@ signal-exit@^4.0.1:
|
||||
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04"
|
||||
integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==
|
||||
|
||||
simple-swizzle@^0.2.2:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
|
||||
integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
|
||||
dependencies:
|
||||
is-arrayish "^0.3.1"
|
||||
|
||||
sisteransi@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
|
||||
@ -9823,15 +9972,6 @@ string-length@^4.0.1:
|
||||
char-regex "^1.0.2"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
"string-width-cjs@npm:string-width@^4.2.0":
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
|
||||
dependencies:
|
||||
emoji-regex "^8.0.0"
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
|
||||
@ -9841,7 +9981,7 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
|
||||
is-fullwidth-code-point "^3.0.0"
|
||||
strip-ansi "^6.0.1"
|
||||
|
||||
string-width@^5.0.0, string-width@^5.0.1, string-width@^5.1.2:
|
||||
string-width@^5.0.0, string-width@^5.0.1:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794"
|
||||
integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==
|
||||
@ -9922,13 +10062,6 @@ string.prototype.trimstart@^1.0.8:
|
||||
define-properties "^1.2.1"
|
||||
es-object-atoms "^1.0.0"
|
||||
|
||||
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
|
||||
dependencies:
|
||||
ansi-regex "^5.0.1"
|
||||
|
||||
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
|
||||
@ -9992,10 +10125,10 @@ style-search@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
|
||||
integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==
|
||||
|
||||
styled-jsx@5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
|
||||
integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
|
||||
styled-jsx@5.1.6:
|
||||
version "5.1.6"
|
||||
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499"
|
||||
integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==
|
||||
dependencies:
|
||||
client-only "0.0.1"
|
||||
|
||||
@ -10702,15 +10835,6 @@ word-wrap@^1.2.5:
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
|
||||
integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==
|
||||
|
||||
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
|
||||
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
|
||||
dependencies:
|
||||
ansi-styles "^4.0.0"
|
||||
string-width "^4.1.0"
|
||||
strip-ansi "^6.0.0"
|
||||
|
||||
wrap-ansi@^6.2.0:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53"
|
||||
|
Loading…
x
Reference in New Issue
Block a user