diff --git a/docker-compose.yml b/docker-compose.yml index 08f00b7c3c..185f1d0e66 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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"] diff --git a/package.json b/package.json index 2352466bf7..1c828d9b6b 100644 --- a/package.json +++ b/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. ", "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", diff --git a/public/intl/messages/ja-JP.json b/public/intl/messages/ja-JP.json index 5a13b4b1bb..abb2c27c39 100644 --- a/public/intl/messages/ja-JP.json +++ b/public/intl/messages/ja-JP.json @@ -1450,7 +1450,7 @@ "label.visits": [ { "type": 0, - "value": "訪問者数" + "value": "訪問数" } ], "label.website": [ diff --git a/public/intl/messages/nb-NO.json b/public/intl/messages/nb-NO.json index 051c362c26..bb2dec35ab 100644 --- a/public/intl/messages/nb-NO.json +++ b/public/intl/messages/nb-NO.json @@ -2,7 +2,7 @@ "label.access-code": [ { "type": 0, - "value": "Access code" + "value": "Tilgangskode" } ], "label.actions": [ @@ -14,31 +14,31 @@ "label.activity": [ { "type": 0, - "value": "Activity log" + "value": "Aktivitetslogg" } ], "label.add": [ { "type": 0, - "value": "Add" + "value": "Legg til" } ], "label.add-description": [ { "type": 0, - "value": "Add description" + "value": "Legg til beskrivelse" } ], "label.add-member": [ { "type": 0, - "value": "Add member" + "value": "Legg til bruker" } ], "label.add-step": [ { "type": 0, - "value": "Add step" + "value": "Legg til steg" } ], "label.add-website": [ @@ -56,7 +56,7 @@ "label.after": [ { "type": 0, - "value": "After" + "value": "Etter" } ], "label.all": [ @@ -80,7 +80,7 @@ "label.average": [ { "type": 0, - "value": "Average" + "value": "Gjennomsnnitt" } ], "label.back": [ @@ -92,7 +92,7 @@ "label.before": [ { "type": 0, - "value": "Before" + "value": "Før" } ], "label.bounce-rate": [ @@ -104,13 +104,13 @@ "label.breakdown": [ { "type": 0, - "value": "Breakdown" + "value": "Nedbrytning" } ], "label.browser": [ { "type": 0, - "value": "Browser" + "value": "Nettleser" } ], "label.browsers": [ @@ -134,31 +134,31 @@ "label.cities": [ { "type": 0, - "value": "Cities" + "value": "Byer" } ], "label.city": [ { "type": 0, - "value": "City" + "value": "By" } ], "label.clear-all": [ { "type": 0, - "value": "Clear all" + "value": "Tøm alle" } ], "label.compare": [ { "type": 0, - "value": "Compare" + "value": "Sammenlign" } ], "label.confirm": [ { "type": 0, - "value": "Confirm" + "value": "Bekreft" } ], "label.confirm-password": [ @@ -170,19 +170,19 @@ "label.contains": [ { "type": 0, - "value": "Contains" + "value": "Inneholder" } ], "label.continue": [ { "type": 0, - "value": "Continue" + "value": "Fortsett" } ], "label.count": [ { "type": 0, - "value": "Count" + "value": "Antall" } ], "label.countries": [ @@ -194,49 +194,49 @@ "label.country": [ { "type": 0, - "value": "Country" + "value": "Land" } ], "label.create": [ { "type": 0, - "value": "Create" + "value": "Opprett" } ], "label.create-report": [ { "type": 0, - "value": "Create report" + "value": "Opprett rapport" } ], "label.create-team": [ { "type": 0, - "value": "Create team" + "value": "Opprett team" } ], "label.create-user": [ { "type": 0, - "value": "Create user" + "value": "Opprett bruker" } ], "label.created": [ { "type": 0, - "value": "Created" + "value": "Opprettet" } ], "label.created-by": [ { "type": 0, - "value": "Created By" + "value": "Opprettet av" } ], "label.current": [ { "type": 0, - "value": "Current" + "value": "Nåværende" } ], "label.current-password": [ @@ -266,7 +266,7 @@ "label.date": [ { "type": 0, - "value": "Date" + "value": "Dato" } ], "label.date-range": [ @@ -278,7 +278,7 @@ "label.day": [ { "type": 0, - "value": "Day" + "value": "Dag" } ], "label.default-date-range": [ @@ -332,13 +332,13 @@ "label.details": [ { "type": 0, - "value": "Details" + "value": "Detaljer" } ], "label.device": [ { "type": 0, - "value": "Device" + "value": "Enhet" } ], "label.devices": [ @@ -356,7 +356,7 @@ "label.does-not-contain": [ { "type": 0, - "value": "Does not contain" + "value": "Innholder ikke" } ], "label.domain": [ @@ -380,13 +380,13 @@ "label.edit-dashboard": [ { "type": 0, - "value": "Edit dashboard" + "value": "Rediger dashboard" } ], "label.edit-member": [ { "type": 0, - "value": "Edit member" + "value": "Rediger bruker" } ], "label.enable-share-url": [ @@ -398,55 +398,55 @@ "label.end-step": [ { "type": 0, - "value": "End Step" + "value": "Avslutt steg" } ], "label.entry": [ { "type": 0, - "value": "Entry URL" + "value": "Inngangs-URL" } ], "label.event": [ { "type": 0, - "value": "Event" + "value": "Hendelse" } ], "label.event-data": [ { "type": 0, - "value": "Event data" + "value": "Hendelsesdata" } ], "label.events": [ { "type": 0, - "value": "Arrangementer" + "value": "Hendelser" } ], "label.exit": [ { "type": 0, - "value": "Exit URL" + "value": "Utgangs-URL" } ], "label.false": [ { "type": 0, - "value": "False" + "value": "Usant" } ], "label.field": [ { "type": 0, - "value": "Field" + "value": "Felt" } ], "label.fields": [ { "type": 0, - "value": "Fields" + "value": "Felt" } ], "label.filter": [ @@ -470,127 +470,127 @@ "label.filters": [ { "type": 0, - "value": "Filters" + "value": "Filter" } ], "label.first-seen": [ { "type": 0, - "value": "First seen" + "value": "Først sett" } ], "label.funnel": [ { "type": 0, - "value": "Funnel" + "value": "Trakt" } ], "label.funnel-description": [ { "type": 0, - "value": "Understand the conversion and drop-off rate of users." + "value": "Forstå konverteringen og drop-off frafallsfrekvens av brukere." } ], "label.goal": [ { "type": 0, - "value": "Goal" + "value": "Mål" } ], "label.goals": [ { "type": 0, - "value": "Goals" + "value": "Mål" } ], "label.goals-description": [ { "type": 0, - "value": "Track your goals for pageviews and events." + "value": "Spor dine mål for sidevisninger og hendelser." } ], "label.greater-than": [ { "type": 0, - "value": "Greater than" + "value": "Mer enn" } ], "label.greater-than-equals": [ { "type": 0, - "value": "Greater than or equals" + "value": "Mer enn eller lik" } ], "label.host": [ { "type": 0, - "value": "Host" + "value": "Vert" } ], "label.hosts": [ { "type": 0, - "value": "Hosts" + "value": "Verter" } ], "label.insights": [ { "type": 0, - "value": "Insights" + "value": "Innsikt" } ], "label.insights-description": [ { "type": 0, - "value": "Dive deeper into your data by using segments and filters." + "value": "Dykk dypere i din data ved bruk av segmentering og filtre." } ], "label.is": [ { "type": 0, - "value": "Is" + "value": "Er" } ], "label.is-not": [ { "type": 0, - "value": "Is not" + "value": "Er ikke" } ], "label.is-not-set": [ { "type": 0, - "value": "Is not set" + "value": "Er ikke satt" } ], "label.is-set": [ { "type": 0, - "value": "Is set" + "value": "Er satt" } ], "label.join": [ { "type": 0, - "value": "Join" + "value": "Bli med" } ], "label.join-team": [ { "type": 0, - "value": "Join team" + "value": "Bli med i teamet" } ], "label.journey": [ { "type": 0, - "value": "Journey" + "value": "Reise" } ], "label.journey-description": [ { "type": 0, - "value": "Understand how users navigate through your website." + "value": "Forstå hvordan brukerene navigerer gjennom din side." } ], "label.language": [ @@ -656,31 +656,31 @@ "label.last-seen": [ { "type": 0, - "value": "Last seen" + "value": "Sist sett" } ], "label.leave": [ { "type": 0, - "value": "Leave" + "value": "Forlat" } ], "label.leave-team": [ { "type": 0, - "value": "Leave team" + "value": "Forlat team" } ], "label.less-than": [ { "type": 0, - "value": "Less than" + "value": "Mindre enn" } ], "label.less-than-equals": [ { "type": 0, - "value": "Less than or equals" + "value": "Mindre enn eller lik" } ], "label.login": [ @@ -698,31 +698,31 @@ "label.manage": [ { "type": 0, - "value": "Manage" + "value": "Administrer" } ], "label.manager": [ { "type": 0, - "value": "Manager" + "value": "Administrator" } ], "label.max": [ { "type": 0, - "value": "Max" + "value": "Maks" } ], "label.member": [ { "type": 0, - "value": "Member" + "value": "Bruker" } ], "label.members": [ { "type": 0, - "value": "Members" + "value": "Brukere" } ], "label.min": [ @@ -746,13 +746,13 @@ "label.my-account": [ { "type": 0, - "value": "My account" + "value": "Min konto" } ], "label.my-websites": [ { "type": 0, - "value": "My websites" + "value": "Mine nettsider" } ], "label.name": [ @@ -770,7 +770,7 @@ "label.none": [ { "type": 0, - "value": "None" + "value": "Ingen" } ], "label.number-of-records": [ @@ -822,7 +822,7 @@ "label.overview": [ { "type": 0, - "value": "Overview" + "value": "Oversikt" } ], "label.owner": [ @@ -834,7 +834,7 @@ "label.page-of": [ { "type": 0, - "value": "Page " + "value": "Side " }, { "type": 1, @@ -842,7 +842,7 @@ }, { "type": 0, - "value": " of " + "value": " av " }, { "type": 1, @@ -858,7 +858,7 @@ "label.pageTitle": [ { "type": 0, - "value": "Page title" + "value": "Sidetittel" } ], "label.pages": [ @@ -876,13 +876,13 @@ "label.path": [ { "type": 0, - "value": "Path" + "value": "Sti" } ], "label.paths": [ { "type": 0, - "value": "Paths" + "value": "Stier" } ], "label.powered-by": [ @@ -898,19 +898,19 @@ "label.previous": [ { "type": 0, - "value": "Previous" + "value": "Forrige" } ], "label.previous-period": [ { "type": 0, - "value": "Previous period" + "value": "Forrige periode" } ], "label.previous-year": [ { "type": 0, - "value": "Previous year" + "value": "Forrige år" } ], "label.profile": [ @@ -922,31 +922,31 @@ "label.properties": [ { "type": 0, - "value": "Properties" + "value": "Egenskaper" } ], "label.property": [ { "type": 0, - "value": "Property" + "value": "Egenskap" } ], "label.queries": [ { "type": 0, - "value": "Queries" + "value": "Forspørsler" } ], "label.query": [ { "type": 0, - "value": "Query" + "value": "Forespørsel" } ], "label.query-parameters": [ { "type": 0, - "value": "Query parameters" + "value": "Forespørsel parametere" } ], "label.realtime": [ @@ -958,13 +958,13 @@ "label.referrer": [ { "type": 0, - "value": "Referrer" + "value": "Henviser" } ], "label.referrers": [ { "type": 0, - "value": "Referanser" + "value": "Henvisere" } ], "label.refresh": [ @@ -976,7 +976,7 @@ "label.regenerate": [ { "type": 0, - "value": "Regenerate" + "value": "Regenerer" } ], "label.region": [ @@ -988,25 +988,25 @@ "label.regions": [ { "type": 0, - "value": "Regions" + "value": "Regioner" } ], "label.remove": [ { "type": 0, - "value": "Remove" + "value": "Fjern" } ], "label.remove-member": [ { "type": 0, - "value": "Remove member" + "value": "Fjern bruker" } ], "label.reports": [ { "type": 0, - "value": "Reports" + "value": "Rapporter" } ], "label.required": [ @@ -1030,43 +1030,43 @@ "label.retention": [ { "type": 0, - "value": "Retention" + "value": "Retensjon" } ], "label.retention-description": [ { "type": 0, - "value": "Measure your website stickiness by tracking how often users return." + "value": "Mål nettstedets klebrighet ved å spore hvor ofte brukere kommer tilbake." } ], "label.revenue": [ { "type": 0, - "value": "Revenue" + "value": "Inntenker" } ], "label.revenue-description": [ { "type": 0, - "value": "Look into your revenue across time." + "value": "Se på inntektene dine over tid." } ], "label.revenue-property": [ { "type": 0, - "value": "Revenue Property" + "value": "Inntektegenskaper" } ], "label.role": [ { "type": 0, - "value": "Role" + "value": "Rolle" } ], "label.run-query": [ { "type": 0, - "value": "Run query" + "value": "Kjør spørring" } ], "label.save": [ @@ -1078,49 +1078,49 @@ "label.screens": [ { "type": 0, - "value": "Screens" + "value": "Skjermer" } ], "label.search": [ { "type": 0, - "value": "Search" + "value": "Søk" } ], "label.select": [ { "type": 0, - "value": "Select" + "value": "Velg" } ], "label.select-date": [ { "type": 0, - "value": "Select date" + "value": "Velg dato" } ], "label.select-role": [ { "type": 0, - "value": "Select role" + "value": "Velg rolle" } ], "label.select-website": [ { "type": 0, - "value": "Select website" + "value": "Velg nettsted" } ], "label.session": [ { "type": 0, - "value": "Session" + "value": "Økt" } ], "label.sessions": [ { "type": 0, - "value": "Sessions" + "value": "Økter" } ], "label.settings": [ @@ -1138,19 +1138,19 @@ "label.single-day": [ { "type": 0, - "value": "Enkelt dag" + "value": "Enkeltdag" } ], "label.start-step": [ { "type": 0, - "value": "Start Step" + "value": "Starttrinn" } ], "label.steps": [ { "type": 0, - "value": "Steps" + "value": "Trinn" } ], "label.sum": [ @@ -1174,55 +1174,55 @@ "label.team-id": [ { "type": 0, - "value": "Team ID" + "value": "Team-ID" } ], "label.team-manager": [ { "type": 0, - "value": "Team manager" + "value": "Teamadministrator" } ], "label.team-member": [ { "type": 0, - "value": "Team member" + "value": "Teammedlem" } ], "label.team-name": [ { "type": 0, - "value": "Team name" + "value": "Teamnavn" } ], "label.team-owner": [ { "type": 0, - "value": "Team owner" + "value": "Teameier" } ], "label.team-view-only": [ { "type": 0, - "value": "Team view only" + "value": "Team (kun visning)" } ], "label.team-websites": [ { "type": 0, - "value": "Team websites" + "value": "Team-nettsteder" } ], "label.teams": [ { "type": 0, - "value": "Teams" + "value": "Team" } ], "label.theme": [ { "type": 0, - "value": "Theme" + "value": "Tema" } ], "label.this-month": [ @@ -1252,7 +1252,7 @@ "label.title": [ { "type": 0, - "value": "Title" + "value": "Tittel" } ], "label.today": [ @@ -1270,13 +1270,13 @@ "label.total": [ { "type": 0, - "value": "Total" + "value": "Totalt" } ], "label.total-records": [ { "type": 0, - "value": "Total records" + "value": "Totalt antall oppføringer" } ], "label.tracking-code": [ @@ -1288,25 +1288,25 @@ "label.transactions": [ { "type": 0, - "value": "Transactions" + "value": "Transaksjoner" } ], "label.transfer": [ { "type": 0, - "value": "Transfer" + "value": "Overfør" } ], "label.transfer-website": [ { "type": 0, - "value": "Transfer website" + "value": "Overfør nettsted" } ], "label.true": [ { "type": 0, - "value": "True" + "value": "Sant" } ], "label.type": [ @@ -1318,7 +1318,7 @@ "label.unique": [ { "type": 0, - "value": "Unique" + "value": "Unike" } ], "label.unique-visitors": [ @@ -1330,7 +1330,7 @@ "label.uniqueCustomers": [ { "type": 0, - "value": "Unique Customers" + "value": "Unike kunder" } ], "label.unknown": [ @@ -1342,13 +1342,13 @@ "label.untitled": [ { "type": 0, - "value": "Untitled" + "value": "Uten tittel" } ], "label.update": [ { "type": 0, - "value": "Update" + "value": "Oppdater" } ], "label.url": [ @@ -1360,19 +1360,19 @@ "label.urls": [ { "type": 0, - "value": "URLs" + "value": "URL-er" } ], "label.user": [ { "type": 0, - "value": "User" + "value": "Bruker" } ], "label.user-property": [ { "type": 0, - "value": "User Property" + "value": "Brukeregenskap" } ], "label.username": [ @@ -1384,7 +1384,7 @@ "label.users": [ { "type": 0, - "value": "Users" + "value": "Brukere" } ], "label.utm": [ @@ -1396,19 +1396,19 @@ "label.utm-description": [ { "type": 0, - "value": "Track your campaigns through UTM parameters." + "value": "Spor kampanjene dine via UTM-parametre." } ], "label.value": [ { "type": 0, - "value": "Value" + "value": "Verdi" } ], "label.view": [ { "type": 0, - "value": "View" + "value": "Vis" } ], "label.view-details": [ @@ -1420,7 +1420,7 @@ "label.view-only": [ { "type": 0, - "value": "View only" + "value": "Kun visning" } ], "label.views": [ @@ -1432,7 +1432,7 @@ "label.views-per-visit": [ { "type": 0, - "value": "Views per visit" + "value": "Visninger per besøk" } ], "label.visit-duration": [ @@ -1450,19 +1450,19 @@ "label.visits": [ { "type": 0, - "value": "Visits" + "value": "Besøk" } ], "label.website": [ { "type": 0, - "value": "Website" + "value": "Nettsted" } ], "label.website-id": [ { "type": 0, - "value": "Website ID" + "value": "Nettsted-ID" } ], "label.websites": [ @@ -1474,19 +1474,19 @@ "label.window": [ { "type": 0, - "value": "Window" + "value": "Vindu" } ], "label.yesterday": [ { "type": 0, - "value": "Yesterday" + "value": "I går" } ], "message.action-confirmation": [ { "type": 0, - "value": "Type " + "value": "Skriv " }, { "type": 1, @@ -1494,7 +1494,7 @@ }, { "type": 0, - "value": " in the box below to confirm." + "value": " i feltet nedenfor for å bekrefte." } ], "message.active-users": [ @@ -1538,7 +1538,7 @@ "message.collected-data": [ { "type": 0, - "value": "Collected data" + "value": "Innsamlede data" } ], "message.confirm-delete": [ @@ -1558,7 +1558,7 @@ "message.confirm-leave": [ { "type": 0, - "value": "Are you sure you want to leave " + "value": "Er du sikker på at du vil forlate " }, { "type": 1, @@ -1572,7 +1572,7 @@ "message.confirm-remove": [ { "type": 0, - "value": "Are you sure you want to remove " + "value": "Er du sikker på at du vil fjerne " }, { "type": 1, @@ -1586,7 +1586,7 @@ "message.confirm-reset": [ { "type": 0, - "value": "Er du sikker på at du vil nullstille " + "value": "Er du sikker på at du vil nullstille statistikken til " }, { "type": 1, @@ -1594,19 +1594,19 @@ }, { "type": 0, - "value": "'s statistikk?" + "value": "?" } ], "message.delete-team-warning": [ { "type": 0, - "value": "Deleting a team will also delete all team websites." + "value": "Å slette et team vil også slette alle teamets nettsteder." } ], "message.delete-website-warning": [ { "type": 0, - "value": "Alle tilknyttede data slettes også." + "value": "Alle tilknyttede data vil også bli slettet." } ], "message.error": [ @@ -1622,7 +1622,7 @@ }, { "type": 0, - "value": " on " + "value": " på " }, { "type": 1, @@ -1650,7 +1650,7 @@ "message.min-password-length": [ { "type": 0, - "value": "Minimum length of " + "value": "Minimumslengde på " }, { "type": 1, @@ -1658,13 +1658,13 @@ }, { "type": 0, - "value": " characters" + "value": " tegn" } ], "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "En ny versjon av Umami " }, { "type": 1, @@ -1672,7 +1672,7 @@ }, { "type": 0, - "value": " is available!" + "value": " er tilgjengelig!" } ], "message.no-data-available": [ @@ -1684,7 +1684,7 @@ "message.no-event-data": [ { "type": 0, - "value": "No event data is available." + "value": "Ingen hendelsesdata er tilgjengelig." } ], "message.no-match-password": [ @@ -1696,25 +1696,25 @@ "message.no-results-found": [ { "type": 0, - "value": "No results were found." + "value": "Ingen resultater funnet." } ], "message.no-team-websites": [ { "type": 0, - "value": "This team does not have any websites." + "value": "Dette teamet har ingen nettsteder." } ], "message.no-teams": [ { "type": 0, - "value": "You have not created any teams." + "value": "Du har ikke opprettet noen team." } ], "message.no-users": [ { "type": 0, - "value": "There are no users." + "value": "Ingen brukere." } ], "message.no-websites-configured": [ @@ -1726,13 +1726,13 @@ "message.page-not-found": [ { "type": 0, - "value": "Side ikke funnet." + "value": "Siden ble ikke funnet." } ], "message.reset-website": [ { "type": 0, - "value": "To reset this website, type " + "value": "For å nullstille dette nettstedet, skriv " }, { "type": 1, @@ -1740,13 +1740,13 @@ }, { "type": 0, - "value": " in the box below to confirm." + "value": " i feltet nedenfor for å bekrefte." } ], "message.reset-website-warning": [ { "type": 0, - "value": "All statistikk for denne nettsiden vil bli slettet, men sporingskoden din vil forbli uberørt." + "value": "All statistikk for dette nettstedet vil bli slettet, men sporingskoden forblir uberørt." } ], "message.saved": [ @@ -1772,19 +1772,19 @@ "message.team-already-member": [ { "type": 0, - "value": "You are already a member of the team." + "value": "Du er allerede medlem av teamet." } ], "message.team-not-found": [ { "type": 0, - "value": "Team not found." + "value": "Teamet ble ikke funnet." } ], "message.team-websites-info": [ { "type": 0, - "value": "Websites can be viewed by anyone on the team." + "value": "Nettsteder kan vises av alle på teamet." } ], "message.tracking-code": [ @@ -1796,37 +1796,37 @@ "message.transfer-team-website-to-user": [ { "type": 0, - "value": "Transfer this website to your account?" + "value": "Overfør dette nettstedet til kontoen din?" } ], "message.transfer-user-website-to-team": [ { "type": 0, - "value": "Select the team to transfer this website to." + "value": "Velg teamet du vil overføre dette nettstedet til." } ], "message.transfer-website": [ { "type": 0, - "value": "Transfer website ownership to your account or another team." + "value": "Overfør eierskapet til nettstedet til din konto eller et annet team." } ], "message.triggered-event": [ { "type": 0, - "value": "Triggered event" + "value": "Utløst hendelse" } ], "message.user-deleted": [ { "type": 0, - "value": "User deleted." + "value": "Bruker slettet." } ], "message.viewed-page": [ { "type": 0, - "value": "Viewed page" + "value": "Vist side" } ], "message.visitor-log": [ @@ -1866,7 +1866,7 @@ "message.visitors-dropped-off": [ { "type": 0, - "value": "Visitors dropped off" + "value": "Besøkende falt fra" } ] } diff --git a/public/intl/messages/zh-CN.json b/public/intl/messages/zh-CN.json index b3e97b9b0f..c2eb1c59af 100644 --- a/public/intl/messages/zh-CN.json +++ b/public/intl/messages/zh-CN.json @@ -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": [ diff --git a/public/intl/messages/zh-TW.json b/public/intl/messages/zh-TW.json index e03059f8d6..d8fb3d42dd 100644 --- a/public/intl/messages/zh-TW.json +++ b/public/intl/messages/zh-TW.json @@ -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": 0, + "value": "在 " + }, { "type": 1, - "value": "event" + "value": "url" }, { "type": 0, - "value": " 在 " + "value": " 上的 " }, { "type": 1, - "value": "url" + "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": "訪客已離開" } ] } diff --git a/src/app/(main)/NavBar.tsx b/src/app/(main)/NavBar.tsx index 6daae0357a..5c8bba01ad 100644 --- a/src/app/(main)/NavBar.tsx +++ b/src/app/(main)/NavBar.tsx @@ -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]); diff --git a/src/app/(main)/console/[[...websiteId]]/page.tsx b/src/app/(main)/console/[[...websiteId]]/page.tsx index 2cbdddcc0a..93eafee470 100644 --- a/src/app/(main)/console/[[...websiteId]]/page.tsx +++ b/src/app/(main)/console/[[...websiteId]]/page.tsx @@ -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) { diff --git a/src/app/(main)/profile/TimezoneSetting.tsx b/src/app/(main)/profile/TimezoneSetting.tsx index 02f3e186f4..00858ac708 100644 --- a/src/app/(main)/profile/TimezoneSetting.tsx +++ b/src/app/(main)/profile/TimezoneSetting.tsx @@ -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(''); diff --git a/src/app/(main)/reports/[reportId]/page.tsx b/src/app/(main)/reports/[reportId]/page.tsx index 690daf4780..85a97d1ca2 100644 --- a/src/app/(main)/reports/[reportId]/page.tsx +++ b/src/app/(main)/reports/[reportId]/page.tsx @@ -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 ; } diff --git a/src/app/(main)/settings/users/[userId]/page.tsx b/src/app/(main)/settings/users/[userId]/page.tsx index d5dc5005dd..3b3a3fac9c 100644 --- a/src/app/(main)/settings/users/[userId]/page.tsx +++ b/src/app/(main)/settings/users/[userId]/page.tsx @@ -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 ; } diff --git a/src/app/(main)/settings/websites/[websiteId]/page.tsx b/src/app/(main)/settings/websites/[websiteId]/page.tsx index f3d87c7883..7e2feaf26e 100644 --- a/src/app/(main)/settings/websites/[websiteId]/page.tsx +++ b/src/app/(main)/settings/websites/[websiteId]/page.tsx @@ -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 ; } diff --git a/src/app/(main)/settings/websites/page.tsx b/src/app/(main)/settings/websites/page.tsx index d073b32b58..d05be0a5c8 100644 --- a/src/app/(main)/settings/websites/page.tsx +++ b/src/app/(main)/settings/websites/page.tsx @@ -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 ; } diff --git a/src/app/(main)/teams/[teamId]/layout.tsx b/src/app/(main)/teams/[teamId]/layout.tsx index e10cdb9431..0452ae9769 100644 --- a/src/app/(main)/teams/[teamId]/layout.tsx +++ b/src/app/(main)/teams/[teamId]/layout.tsx @@ -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 ( {children} diff --git a/src/app/(main)/teams/[teamId]/settings/members/page.tsx b/src/app/(main)/teams/[teamId]/settings/members/page.tsx index fbee6a8ea0..9810f7a20f 100644 --- a/src/app/(main)/teams/[teamId]/settings/members/page.tsx +++ b/src/app/(main)/teams/[teamId]/settings/members/page.tsx @@ -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 ; } diff --git a/src/app/(main)/teams/[teamId]/settings/team/page.tsx b/src/app/(main)/teams/[teamId]/settings/team/page.tsx index 0c4dd2012b..f15d5fb61f 100644 --- a/src/app/(main)/teams/[teamId]/settings/team/page.tsx +++ b/src/app/(main)/teams/[teamId]/settings/team/page.tsx @@ -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 ; } diff --git a/src/app/(main)/teams/[teamId]/settings/websites/page.tsx b/src/app/(main)/teams/[teamId]/settings/websites/page.tsx index cfb465fb42..6709eb6715 100644 --- a/src/app/(main)/teams/[teamId]/settings/websites/page.tsx +++ b/src/app/(main)/teams/[teamId]/settings/websites/page.tsx @@ -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 ; } diff --git a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx index fa5ab69423..ddeba789d1 100644 --- a/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx +++ b/src/app/(main)/websites/[websiteId]/WebsiteChart.tsx @@ -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'} /> ); } diff --git a/src/app/(main)/websites/[websiteId]/compare/page.tsx b/src/app/(main)/websites/[websiteId]/compare/page.tsx index b3009fcaaa..bdd29bd54f 100644 --- a/src/app/(main)/websites/[websiteId]/compare/page.tsx +++ b/src/app/(main)/websites/[websiteId]/compare/page.tsx @@ -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 ; } diff --git a/src/app/(main)/websites/[websiteId]/events/page.tsx b/src/app/(main)/websites/[websiteId]/events/page.tsx index b5dc4d62ca..1b88824452 100644 --- a/src/app/(main)/websites/[websiteId]/events/page.tsx +++ b/src/app/(main)/websites/[websiteId]/events/page.tsx @@ -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 ; } diff --git a/src/app/(main)/websites/[websiteId]/layout.tsx b/src/app/(main)/websites/[websiteId]/layout.tsx index f8756ea3e7..1df69cd316 100644 --- a/src/app/(main)/websites/[websiteId]/layout.tsx +++ b/src/app/(main)/websites/[websiteId]/layout.tsx @@ -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 {children}; } diff --git a/src/app/(main)/websites/[websiteId]/page.tsx b/src/app/(main)/websites/[websiteId]/page.tsx index 49bca9b6f4..d3aa1633ac 100644 --- a/src/app/(main)/websites/[websiteId]/page.tsx +++ b/src/app/(main)/websites/[websiteId]/page.tsx @@ -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 ; } diff --git a/src/app/(main)/websites/[websiteId]/realtime/page.tsx b/src/app/(main)/websites/[websiteId]/realtime/page.tsx index 0ca7ffd83c..f205caddfc 100644 --- a/src/app/(main)/websites/[websiteId]/realtime/page.tsx +++ b/src/app/(main)/websites/[websiteId]/realtime/page.tsx @@ -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 ; } diff --git a/src/app/(main)/websites/[websiteId]/reports/page.tsx b/src/app/(main)/websites/[websiteId]/reports/page.tsx index caa805a63c..15c79de9a6 100644 --- a/src/app/(main)/websites/[websiteId]/reports/page.tsx +++ b/src/app/(main)/websites/[websiteId]/reports/page.tsx @@ -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 ; } diff --git a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.module.css b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.module.css index b49230c7b8..fb830d3822 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.module.css +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.module.css @@ -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; } diff --git a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx index fd498ac3ab..642b93d996 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/SessionActivity.tsx @@ -42,7 +42,7 @@ export function SessionActivity({ {eventName ? : } -
{eventName || urlPath}
+
{eventName || urlPath}
); diff --git a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/page.tsx b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/page.tsx index 952e8cc580..f4882880cb 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/page.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/[sessionId]/page.tsx @@ -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 ; } diff --git a/src/app/(main)/websites/[websiteId]/sessions/page.tsx b/src/app/(main)/websites/[websiteId]/sessions/page.tsx index 771f682ddc..d1ff96f58a 100644 --- a/src/app/(main)/websites/[websiteId]/sessions/page.tsx +++ b/src/app/(main)/websites/[websiteId]/sessions/page.tsx @@ -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 ; } diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 999cea0321..3c0ed43c9c 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -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'; diff --git a/src/app/share/[...shareId]/page.tsx b/src/app/share/[...shareId]/page.tsx index e8ca8e607e..c06274aa03 100644 --- a/src/app/share/[...shareId]/page.tsx +++ b/src/app/share/[...shareId]/page.tsx @@ -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 ; } diff --git a/src/components/charts/BarChart.tsx b/src/components/charts/BarChart.tsx index eadc4af738..7c16730e7b 100644 --- a/src/components/charts/BarChart.tsx +++ b/src/components/charts/BarChart.tsx @@ -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, diff --git a/src/components/common/Favicon.tsx b/src/components/common/Favicon.tsx index e78bdbc7de..47c65aab14 100644 --- a/src/components/common/Favicon.tsx +++ b/src/components/common/Favicon.tsx @@ -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; } diff --git a/src/components/common/TypeIcon.tsx b/src/components/common/TypeIcon.tsx index d617e75925..2a180445fe 100644 --- a/src/components/common/TypeIcon.tsx +++ b/src/components/common/TypeIcon.tsx @@ -12,9 +12,12 @@ export function TypeIcon({ return ( <> { + e.currentTarget.src = `${process.env.basePath || ''}/images/${type}/unknown.png`; + }} alt={value} width={type === 'country' ? undefined : 16} height={type === 'country' ? undefined : 16} diff --git a/src/components/hooks/queries/useWebsiteValues.ts b/src/components/hooks/queries/useWebsiteValues.ts index 68e950f266..73a7c75536 100644 --- a/src/components/hooks/queries/useWebsiteValues.ts +++ b/src/components/hooks/queries/useWebsiteValues.ts @@ -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), }); diff --git a/src/components/hooks/useFormat.ts b/src/components/hooks/useFormat.ts index 631b3f03bb..1003072165 100644 --- a/src/components/hooks/useFormat.ts +++ b/src/components/hooks/useFormat.ts @@ -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; diff --git a/src/components/hooks/useLanguageNames.ts b/src/components/hooks/useLanguageNames.ts index 276faa1499..07b36a2c70 100644 --- a/src/components/hooks/useLanguageNames.ts +++ b/src/components/hooks/useLanguageNames.ts @@ -28,7 +28,7 @@ export function useLanguageNames(locale) { } }, [locale]); - return list; + return { languageNames: list }; } export default useLanguageNames; diff --git a/src/components/metrics/CitiesTable.tsx b/src/components/metrics/CitiesTable.tsx index b3573b5c36..fd628e7fa7 100644 --- a/src/components/metrics/CitiesTable.tsx +++ b/src/components/metrics/CitiesTable.tsx @@ -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 ( - - {country && } + + {country && ( + {country} + )} ); }; @@ -32,6 +31,7 @@ export function CitiesTable(props: MetricsTableProps) { metric={formatMessage(labels.visitors)} dataFilter={emptyFilter} renderLabel={renderLink} + searchFormattedValues={true} /> ); } diff --git a/src/components/metrics/CountriesTable.tsx b/src/components/metrics/CountriesTable.tsx index c1fc28318c..f4560ae347 100644 --- a/src/components/metrics/CountriesTable.tsx +++ b/src/components/metrics/CountriesTable.tsx @@ -12,7 +12,11 @@ export function CountriesTable({ ...props }: MetricsTableProps) { const renderLink = ({ x: code }) => { return ( - + ); @@ -25,6 +29,7 @@ export function CountriesTable({ ...props }: MetricsTableProps) { type="country" metric={formatMessage(labels.visitors)} renderLabel={renderLink} + searchFormattedValues={true} /> ); } diff --git a/src/components/metrics/DevicesTable.tsx b/src/components/metrics/DevicesTable.tsx index f2f3f1aabe..c25afe4fa8 100644 --- a/src/components/metrics/DevicesTable.tsx +++ b/src/components/metrics/DevicesTable.tsx @@ -23,6 +23,7 @@ export function DevicesTable(props: MetricsTableProps) { type="device" metric={formatMessage(labels.visitors)} renderLabel={renderLink} + searchFormattedValues={true} /> ); } diff --git a/src/components/metrics/EventsChart.tsx b/src/components/metrics/EventsChart.tsx index f5b283449b..2ba2caeecc 100644 --- a/src/components/metrics/EventsChart.tsx +++ b/src/components/metrics/EventsChart.tsx @@ -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'} /> ); } diff --git a/src/components/metrics/LanguagesTable.tsx b/src/components/metrics/LanguagesTable.tsx index f4b0b50386..24b62046f6 100644 --- a/src/components/metrics/LanguagesTable.tsx +++ b/src/components/metrics/LanguagesTable.tsx @@ -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
{formatLanguage(x)}
; }; return ( @@ -24,6 +24,7 @@ export function LanguagesTable({ metric={formatMessage(labels.visitors)} onDataLoad={data => onDataLoad?.(percentFilter(data))} renderLabel={renderLabel} + searchFormattedValues={true} /> ); } diff --git a/src/components/metrics/MetricsTable.tsx b/src/components/metrics/MetricsTable.tsx index 4ca3ff522e..4db599b960 100644 --- a/src/components/metrics/MetricsTable.tsx +++ b/src/components/metrics/MetricsTable.tsx @@ -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; diff --git a/src/components/metrics/PageviewsChart.tsx b/src/components/metrics/PageviewsChart.tsx index 6ca0309494..6274defc09 100644 --- a/src/components/metrics/PageviewsChart.tsx +++ b/src/components/metrics/PageviewsChart.tsx @@ -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)} /> ); diff --git a/src/components/metrics/RegionsTable.tsx b/src/components/metrics/RegionsTable.tsx index b4071f50ec..0c3a931fd5 100644 --- a/src/components/metrics/RegionsTable.tsx +++ b/src/components/metrics/RegionsTable.tsx @@ -25,6 +25,7 @@ export function RegionsTable(props: MetricsTableProps) { metric={formatMessage(labels.visitors)} dataFilter={emptyFilter} renderLabel={renderLink} + searchFormattedValues={true} /> ); } diff --git a/src/lang/ja-JP.json b/src/lang/ja-JP.json index bc59f1140b..ce4001f430 100644 --- a/src/lang/ja-JP.json +++ b/src/lang/ja-JP.json @@ -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サイト", diff --git a/src/lang/nb-NO.json b/src/lang/nb-NO.json index 55d211874d..7c691002d2 100644 --- a/src/lang/nb-NO.json +++ b/src/lang/nb-NO.json @@ -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" + } diff --git a/src/lang/zh-CN.json b/src/lang/zh-CN.json index 741d2de0ec..b1ee86bd3f 100644 --- a/src/lang/zh-CN.json +++ b/src/lang/zh-CN.json @@ -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", diff --git a/src/lang/zh-TW.json b/src/lang/zh-TW.json index a2c5d2c31b..46cdbde1fc 100644 --- a/src/lang/zh-TW.json +++ b/src/lang/zh-TW.json @@ -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 的 ... 區段中。", - "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 的 ... 區段中。", + "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": "訪客已離開" } diff --git a/src/lib/auth.ts b/src/lib/auth.ts index 12fb0a2817..7b8ac8238a 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -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()); diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index b588ec84e5..5f0248b49c 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -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, diff --git a/src/lib/date.ts b/src/lib/date.ts index b731140cf2..b7755ffc24 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -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) { diff --git a/src/lib/detect.ts b/src/lib/detect.ts index 56a037ec49..c3ce6feedb 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -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, diff --git a/src/lib/load.ts b/src/lib/load.ts index 8cddeaa9e5..5b834ca86c 100644 --- a/src/lib/load.ts +++ b/src/lib/load.ts @@ -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 { 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 { export async function fetchSession(websiteId: string, sessionId: string): Promise { 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, diff --git a/src/lib/middleware.ts b/src/lib/middleware.ts index f13b5c723f..3f7b950466 100644 --- a/src/lib/middleware.ts +++ b/src/lib/middleware.ts @@ -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); diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index 32ac65eb5f..a8f7eb0633 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -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 = '') { diff --git a/src/lib/session.ts b/src/lib/session.ts index ca145c04bb..5311e3fda6 100644 --- a/src/lib/session.ts +++ b/src/lib/session.ts @@ -88,5 +88,5 @@ export async function getSession(req: NextApiRequestCollect): Promise `Invalid timezone`, - value => moment.tz.zone(value) !== null, + value => isValidTimezone(value), ); export const UnitTypeTest = yup.string().test( diff --git a/src/pages/api/auth/login.ts b/src/pages/api/auth/login.ts index 51c53184e8..ab17c93766 100644 --- a/src/pages/api/auth/login.ts +++ b/src/pages/api/auth/login.ts @@ -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 }); diff --git a/src/pages/api/auth/logout.ts b/src/pages/api/auth/logout.ts index 715fda6223..f1604989f9 100644 --- a/src/pages/api/auth/logout.ts +++ b/src/pages/api/auth/logout.ts @@ -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); diff --git a/src/pages/api/auth/sso.ts b/src/pages/api/auth/sso.ts index 7b1eef60d8..c5560cb1a1 100644 --- a/src/pages/api/auth/sso.ts +++ b/src/pages/api/auth/sso.ts @@ -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 }); diff --git a/src/pages/api/reports/funnel.ts b/src/pages/api/reports/funnel.ts index 35759a3030..f3ea41aa6e 100644 --- a/src/pages/api/reports/funnel.ts +++ b/src/pages/api/reports/funnel.ts @@ -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) diff --git a/src/pages/api/send.ts b/src/pages/api/send.ts index fb4e90c744..ddaaca94fc 100644 --- a/src/pages/api/send.ts +++ b/src/pages/api/send.ts @@ -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 diff --git a/src/pages/api/websites/[websiteId]/values.ts b/src/pages/api/websites/[websiteId]/values.ts index 364261d9dc..53d717a511 100644 --- a/src/pages/api/websites/[websiteId]/values.ts +++ b/src/pages/api/websites/[websiteId]/values.ts @@ -49,13 +49,7 @@ export default async (req: NextApiRequestQueryBody, 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, diff --git a/src/queries/analytics/getValues.ts b/src/queries/analytics/getValues.ts index 8b1afb3f0b..f303faff7e 100644 --- a/src/queries/analytics/getValues.ts +++ b/src/queries/analytics/getValues.ts @@ -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, }, ); } diff --git a/src/queries/analytics/getWebsiteDateRange.ts b/src/queries/analytics/getWebsiteDateRange.ts index a4daaafc70..ef07712eb7 100644 --- a/src/queries/analytics/getWebsiteDateRange.ts +++ b/src/queries/analytics/getWebsiteDateRange.ts @@ -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} `, diff --git a/src/queries/analytics/reports/getFunnel.ts b/src/queries/analytics/reports/getFunnel.ts index f9ceb85cd1..3a81157fd9 100644 --- a/src/queries/analytics/reports/getFunnel.ts +++ b/src/queries/analytics/reports/getFunnel.ts @@ -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 diff --git a/src/queries/prisma/website.ts b/src/queries/prisma/website.ts index c24cdd0d23..dc1ec438b3 100644 --- a/src/queries/prisma/website.ts +++ b/src/queries/prisma/website.ts @@ -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; diff --git a/src/tracker/index.js b/src/tracker/index.js index c17a76e8df..9fa560e6dc 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -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 */ diff --git a/yarn.lock b/yarn.lock index cccf0949e7..10fe1caea6 100644 --- a/yarn.lock +++ b/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-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-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-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-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-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-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-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-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@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@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@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@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@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@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-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"