mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-05 17:05:46 +01:00
commit
d76603b5b7
28
.github/workflows/cd-cloud.yml
vendored
Normal file
28
.github/workflows/cd-cloud.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: Create docker images
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- analytics
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build, push, and deploy
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Generate random hash
|
||||
id: random_hash
|
||||
run: echo "hash=$(openssl rand -hex 4)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: mr-smithers-excellent/docker-build-push@v6
|
||||
name: Build & push Docker image to docker.io
|
||||
with:
|
||||
image: umamisoftware/umami
|
||||
tags: cloud-${{ steps.random_hash.outputs.hash }}, cloud-latest
|
||||
buildArgs: DATABASE_TYPE=postgresql
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
19
.github/workflows/cd-manual.yml
vendored
19
.github/workflows/cd-manual.yml
vendored
@ -20,11 +20,26 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Extract version parts from input
|
||||
id: extract_version
|
||||
run: |
|
||||
echo "version=$(echo ${{ github.event.inputs.version }})" >> $GITHUB_ENV
|
||||
echo "major=$(echo ${{ github.event.inputs.version }} | cut -d. -f1)" >> $GITHUB_ENV
|
||||
echo "minor=$(echo ${{ github.event.inputs.version }} | cut -d. -f2)" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate tags
|
||||
id: generate_tags
|
||||
run: |
|
||||
echo "tag_major=$(echo ${{ matrix.db-type }}-${{ env.major }})" >> $GITHUB_ENV
|
||||
echo "tag_minor=$(echo ${{ matrix.db-type }}-${{ env.major }}.${{ env.minor }})" >> $GITHUB_ENV
|
||||
echo "tag_patch=$(echo ${{ matrix.db-type }}-${{ env.version }})" >> $GITHUB_ENV
|
||||
echo "tag_latest=$(echo ${{ matrix.db-type }}-latest)" >> $GITHUB_ENV
|
||||
|
||||
- uses: mr-smithers-excellent/docker-build-push@v6
|
||||
name: Build & push Docker image to ghcr.io for ${{ matrix.db-type }}
|
||||
with:
|
||||
image: umami
|
||||
tags: ${{ matrix.db-type }}-${{ inputs.version }}, ${{ matrix.db-type }}-latest
|
||||
tags: ${{ env.tag_major }}, ${{ env.tag_minor }}, ${{ env.tag_patch }}, ${{ env.tag_latest }}
|
||||
buildArgs: DATABASE_TYPE=${{ matrix.db-type }}
|
||||
registry: ghcr.io
|
||||
multiPlatform: true
|
||||
@ -36,7 +51,7 @@ jobs:
|
||||
name: Build & push Docker image to docker.io for ${{ matrix.db-type }}
|
||||
with:
|
||||
image: umamisoftware/umami
|
||||
tags: ${{ matrix.db-type }}-${{ inputs.version }}, ${{ matrix.db-type }}-latest
|
||||
tags: ${{ env.tag_major }}, ${{ env.tag_minor }}, ${{ env.tag_patch }}, ${{ env.tag_latest }}
|
||||
buildArgs: DATABASE_TYPE=${{ matrix.db-type }}
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
|
14
.github/workflows/cd.yml
vendored
14
.github/workflows/cd.yml
vendored
@ -17,14 +17,21 @@ jobs:
|
||||
|
||||
- name: Set env
|
||||
run: |
|
||||
echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
echo "NOW=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate tags
|
||||
id: generate_tags
|
||||
run: |
|
||||
echo "tag_patch=$(echo ${{ matrix.db-type }})-${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV
|
||||
echo "tag_minor=$(echo ${{ matrix.db-type }})-$(echo ${GITHUB_REF#refs/tags/} | cut -d. -f1,2)" >> $GITHUB_ENV
|
||||
echo "tag_major=$(echo ${{ matrix.db-type }})-$(echo ${GITHUB_REF#refs/tags/} | cut -d. -f1)" >> $GITHUB_ENV
|
||||
echo "tag_latest=$(echo ${{ matrix.db-type }})-latest" >> $GITHUB_ENV
|
||||
|
||||
- uses: mr-smithers-excellent/docker-build-push@v6
|
||||
name: Build & push Docker image to ghcr.io for ${{ matrix.db-type }}
|
||||
with:
|
||||
image: umami
|
||||
tags: ${{ matrix.db-type }}-${{ env.RELEASE_VERSION }}, ${{ matrix.db-type }}-latest
|
||||
tags: ${{ env.tag_major }}, ${{ env.tag_minor }}, ${{ env.tag_patch }}, ${{ env.tag_latest }}
|
||||
buildArgs: DATABASE_TYPE=${{ matrix.db-type }}
|
||||
registry: ghcr.io
|
||||
multiPlatform: true
|
||||
@ -32,12 +39,11 @@ jobs:
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
|
||||
- uses: mr-smithers-excellent/docker-build-push@v6
|
||||
name: Build & push Docker image to docker.io for ${{ matrix.db-type }}
|
||||
with:
|
||||
image: umamisoftware/umami
|
||||
tags: ${{ matrix.db-type }}-${{ env.RELEASE_VERSION }}, ${{ matrix.db-type }}-latest
|
||||
tags: ${{ env.tag_major }}, ${{ env.tag_minor }}, ${{ env.tag_patch }}, ${{ env.tag_latest }}
|
||||
buildArgs: DATABASE_TYPE=${{ matrix.db-type }}
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
|
77
db/clickhouse/migrations/04_add_tag.sql
Normal file
77
db/clickhouse/migrations/04_add_tag.sql
Normal file
@ -0,0 +1,77 @@
|
||||
-- add tag column
|
||||
ALTER TABLE umami.website_event ADD COLUMN "tag" String AFTER "event_name";
|
||||
ALTER TABLE umami.website_event_stats_hourly ADD COLUMN "tag" SimpleAggregateFunction(groupArrayArray, Array(String)) AFTER "max_time";
|
||||
|
||||
-- update materialized view
|
||||
DROP TABLE umami.website_event_stats_hourly_mv;
|
||||
|
||||
CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv
|
||||
TO umami.website_event_stats_hourly
|
||||
AS
|
||||
SELECT
|
||||
website_id,
|
||||
session_id,
|
||||
visit_id,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
city,
|
||||
entry_url,
|
||||
exit_url,
|
||||
url_paths as url_path,
|
||||
url_query,
|
||||
referrer_domain,
|
||||
page_title,
|
||||
event_type,
|
||||
event_name,
|
||||
views,
|
||||
min_time,
|
||||
max_time,
|
||||
tag,
|
||||
timestamp as created_at
|
||||
FROM (SELECT
|
||||
website_id,
|
||||
session_id,
|
||||
visit_id,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
city,
|
||||
argMinState(url_path, created_at) entry_url,
|
||||
argMaxState(url_path, created_at) exit_url,
|
||||
arrayFilter(x -> x != '', groupArray(url_path)) as url_paths,
|
||||
arrayFilter(x -> x != '', groupArray(url_query)) url_query,
|
||||
arrayFilter(x -> x != '', groupArray(referrer_domain)) referrer_domain,
|
||||
arrayFilter(x -> x != '', groupArray(page_title)) page_title,
|
||||
event_type,
|
||||
if(event_type = 2, groupArray(event_name), []) event_name,
|
||||
sumIf(1, event_type = 1) views,
|
||||
min(created_at) min_time,
|
||||
max(created_at) max_time,
|
||||
arrayFilter(x -> x != '', groupArray(tag)) tag,
|
||||
toStartOfHour(created_at) timestamp
|
||||
FROM umami.website_event
|
||||
GROUP BY website_id,
|
||||
session_id,
|
||||
visit_id,
|
||||
hostname,
|
||||
browser,
|
||||
os,
|
||||
device,
|
||||
screen,
|
||||
language,
|
||||
country,
|
||||
subdivision1,
|
||||
city,
|
||||
event_type,
|
||||
timestamp);
|
@ -26,6 +26,7 @@ CREATE TABLE umami.website_event
|
||||
--events
|
||||
event_type UInt32,
|
||||
event_name String,
|
||||
tag String,
|
||||
created_at DateTime('UTC'),
|
||||
job_id Nullable(UUID)
|
||||
)
|
||||
@ -96,6 +97,7 @@ CREATE TABLE umami.website_event_stats_hourly
|
||||
views SimpleAggregateFunction(sum, UInt64),
|
||||
min_time SimpleAggregateFunction(min, DateTime('UTC')),
|
||||
max_time SimpleAggregateFunction(max, DateTime('UTC')),
|
||||
tag SimpleAggregateFunction(groupArrayArray, Array(String)),
|
||||
created_at Datetime('UTC')
|
||||
)
|
||||
ENGINE = AggregatingMergeTree
|
||||
@ -136,6 +138,7 @@ SELECT
|
||||
views,
|
||||
min_time,
|
||||
max_time,
|
||||
tag,
|
||||
timestamp as created_at
|
||||
FROM (SELECT
|
||||
website_id,
|
||||
@ -161,6 +164,7 @@ FROM (SELECT
|
||||
sumIf(1, event_type = 1) views,
|
||||
min(created_at) min_time,
|
||||
max(created_at) max_time,
|
||||
arrayFilter(x -> x != '', groupArray(tag)) tag,
|
||||
toStartOfHour(created_at) timestamp
|
||||
FROM umami.website_event
|
||||
GROUP BY website_id,
|
||||
|
@ -11,7 +11,7 @@ CREATE TABLE `user` (
|
||||
UNIQUE INDEX `user_user_id_key`(`user_id`),
|
||||
UNIQUE INDEX `user_username_key`(`username`),
|
||||
PRIMARY KEY (`user_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `session` (
|
||||
@ -33,7 +33,7 @@ CREATE TABLE `session` (
|
||||
INDEX `session_created_at_idx`(`created_at`),
|
||||
INDEX `session_website_id_idx`(`website_id`),
|
||||
PRIMARY KEY (`session_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `website` (
|
||||
@ -53,7 +53,7 @@ CREATE TABLE `website` (
|
||||
INDEX `website_created_at_idx`(`created_at`),
|
||||
INDEX `website_share_id_idx`(`share_id`),
|
||||
PRIMARY KEY (`website_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `website_event` (
|
||||
@ -76,7 +76,7 @@ CREATE TABLE `website_event` (
|
||||
INDEX `website_event_website_id_created_at_idx`(`website_id`, `created_at`),
|
||||
INDEX `website_event_website_id_session_id_created_at_idx`(`website_id`, `session_id`, `created_at`),
|
||||
PRIMARY KEY (`event_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `event_data` (
|
||||
@ -95,7 +95,7 @@ CREATE TABLE `event_data` (
|
||||
INDEX `event_data_website_event_id_idx`(`website_event_id`),
|
||||
INDEX `event_data_website_id_website_event_id_created_at_idx`(`website_id`, `website_event_id`, `created_at`),
|
||||
PRIMARY KEY (`event_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `team` (
|
||||
@ -109,7 +109,7 @@ CREATE TABLE `team` (
|
||||
UNIQUE INDEX `team_access_code_key`(`access_code`),
|
||||
INDEX `team_access_code_idx`(`access_code`),
|
||||
PRIMARY KEY (`team_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `team_user` (
|
||||
@ -124,7 +124,7 @@ CREATE TABLE `team_user` (
|
||||
INDEX `team_user_team_id_idx`(`team_id`),
|
||||
INDEX `team_user_user_id_idx`(`user_id`),
|
||||
PRIMARY KEY (`team_user_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `team_website` (
|
||||
@ -137,7 +137,7 @@ CREATE TABLE `team_website` (
|
||||
INDEX `team_website_team_id_idx`(`team_id`),
|
||||
INDEX `team_website_website_id_idx`(`website_id`),
|
||||
PRIMARY KEY (`team_website_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddSystemUser
|
||||
INSERT INTO user (user_id, username, role, password) VALUES ('41e2b680-648e-4b09-bcd7-3e2b10c06264' , 'admin', 'admin', '$2b$10$BUli0c.muyCW1ErNJc3jL.vFRFtFJWrT8/GcR4A.sUdCznaXiqFXa');
|
@ -21,7 +21,7 @@ CREATE TABLE `session_data` (
|
||||
INDEX `session_data_website_id_idx`(`website_id`),
|
||||
INDEX `session_data_session_id_idx`(`session_id`),
|
||||
PRIMARY KEY (`session_data_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `report` (
|
||||
@ -41,7 +41,7 @@ CREATE TABLE `report` (
|
||||
INDEX `report_type_idx`(`type`),
|
||||
INDEX `report_name_idx`(`name`),
|
||||
PRIMARY KEY (`report_id`)
|
||||
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- EventData migration
|
||||
UPDATE event_data
|
||||
|
5
db/mysql/migrations/07_add_tag/migration.sql
Normal file
5
db/mysql/migrations/07_add_tag/migration.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE `website_event` ADD COLUMN `tag` VARCHAR(50) NULL;
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX `website_event_website_id_created_at_tag_idx` ON `website_event`(`website_id`, `created_at`, `tag`);
|
@ -102,6 +102,7 @@ model WebsiteEvent {
|
||||
pageTitle String? @map("page_title") @db.VarChar(500)
|
||||
eventType Int @default(1) @map("event_type") @db.UnsignedInt
|
||||
eventName String? @map("event_name") @db.VarChar(50)
|
||||
tag String? @db.VarChar(50)
|
||||
|
||||
eventData EventData[]
|
||||
session Session @relation(fields: [sessionId], references: [id])
|
||||
@ -116,6 +117,7 @@ model WebsiteEvent {
|
||||
@@index([websiteId, createdAt, referrerDomain])
|
||||
@@index([websiteId, createdAt, pageTitle])
|
||||
@@index([websiteId, createdAt, eventName])
|
||||
@@index([websiteId, createdAt, tag])
|
||||
@@index([websiteId, sessionId, createdAt])
|
||||
@@index([websiteId, visitId, createdAt])
|
||||
@@map("website_event")
|
||||
|
5
db/postgresql/migrations/07_add_tag/migration.sql
Normal file
5
db/postgresql/migrations/07_add_tag/migration.sql
Normal file
@ -0,0 +1,5 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "website_event" ADD COLUMN "tag" VARCHAR(50);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "website_event_website_id_created_at_tag_idx" ON "website_event"("website_id", "created_at", "tag");
|
@ -102,6 +102,7 @@ model WebsiteEvent {
|
||||
pageTitle String? @map("page_title") @db.VarChar(500)
|
||||
eventType Int @default(1) @map("event_type") @db.Integer
|
||||
eventName String? @map("event_name") @db.VarChar(50)
|
||||
tag String? @db.VarChar(50)
|
||||
|
||||
eventData EventData[]
|
||||
session Session @relation(fields: [sessionId], references: [id])
|
||||
@ -111,11 +112,13 @@ model WebsiteEvent {
|
||||
@@index([visitId])
|
||||
@@index([websiteId])
|
||||
@@index([websiteId, createdAt])
|
||||
|
||||
@@index([websiteId, createdAt, urlPath])
|
||||
@@index([websiteId, createdAt, urlQuery])
|
||||
@@index([websiteId, createdAt, referrerDomain])
|
||||
@@index([websiteId, createdAt, pageTitle])
|
||||
@@index([websiteId, createdAt, eventName])
|
||||
@@index([websiteId, createdAt, tag])
|
||||
@@index([websiteId, sessionId, createdAt])
|
||||
@@index([websiteId, visitId, createdAt])
|
||||
@@map("website_event")
|
||||
|
2
next-env.d.ts
vendored
2
next-env.d.ts
vendored
@ -3,4 +3,4 @@
|
||||
/// <reference types="next/navigation-types/compat/navigation" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/basic-features/typescript for more information.
|
||||
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.
|
||||
|
@ -3,6 +3,8 @@ require('dotenv').config();
|
||||
const path = require('path');
|
||||
const pkg = require('./package.json');
|
||||
|
||||
const TRACKER_SCRIPT = '/script.js';
|
||||
|
||||
const basePath = process.env.BASE_PATH;
|
||||
const collectApiEndpoint = process.env.COLLECT_API_ENDPOINT;
|
||||
const cloudMode = process.env.CLOUD_MODE;
|
||||
@ -14,6 +16,7 @@ const forceSSL = process.env.FORCE_SSL;
|
||||
const frameAncestors = process.env.ALLOWED_FRAME_URLS;
|
||||
const privateMode = process.env.PRIVATE_MODE;
|
||||
const trackerScriptName = process.env.TRACKER_SCRIPT_NAME;
|
||||
const trackerScriptURL = process.env.TRACKER_SCRIPT_URL;
|
||||
|
||||
const contentSecurityPolicy = [
|
||||
`default-src 'self'`,
|
||||
@ -24,7 +27,7 @@ const contentSecurityPolicy = [
|
||||
`frame-ancestors 'self' ${frameAncestors}`,
|
||||
];
|
||||
|
||||
const headers = [
|
||||
const defaultHeaders = [
|
||||
{
|
||||
key: 'X-DNS-Prefetch-Control',
|
||||
value: 'on',
|
||||
@ -39,14 +42,43 @@ const headers = [
|
||||
];
|
||||
|
||||
if (forceSSL) {
|
||||
headers.push({
|
||||
defaultHeaders.push({
|
||||
key: 'Strict-Transport-Security',
|
||||
value: 'max-age=63072000; includeSubDomains; preload',
|
||||
});
|
||||
}
|
||||
|
||||
const trackerHeaders = [
|
||||
{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: '*',
|
||||
},
|
||||
{
|
||||
key: 'Cache-Control',
|
||||
value: 'public, max-age=86400, must-revalidate',
|
||||
},
|
||||
];
|
||||
|
||||
const headers = [
|
||||
{
|
||||
source: '/:path*',
|
||||
headers: defaultHeaders,
|
||||
},
|
||||
{
|
||||
source: TRACKER_SCRIPT,
|
||||
headers: trackerHeaders,
|
||||
},
|
||||
];
|
||||
|
||||
const rewrites = [];
|
||||
|
||||
if (trackerScriptURL) {
|
||||
rewrites.push({
|
||||
source: TRACKER_SCRIPT,
|
||||
destination: trackerScriptURL,
|
||||
});
|
||||
}
|
||||
|
||||
if (collectApiEndpoint) {
|
||||
rewrites.push({
|
||||
source: collectApiEndpoint,
|
||||
@ -54,19 +86,6 @@ if (collectApiEndpoint) {
|
||||
});
|
||||
}
|
||||
|
||||
if (trackerScriptName) {
|
||||
const names = trackerScriptName?.split(',').map(name => name.trim());
|
||||
|
||||
if (names) {
|
||||
names.forEach(name => {
|
||||
rewrites.push({
|
||||
source: `/${name.replace(/^\/+/, '')}`,
|
||||
destination: '/script.js',
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const redirects = [
|
||||
{
|
||||
source: '/settings',
|
||||
@ -85,6 +104,27 @@ const redirects = [
|
||||
},
|
||||
];
|
||||
|
||||
// Adding rewrites + headers for all alternative tracker script names.
|
||||
if (trackerScriptName) {
|
||||
const names = trackerScriptName?.split(',').map(name => name.trim());
|
||||
|
||||
if (names) {
|
||||
names.forEach(name => {
|
||||
const normalizedSource = `/${name.replace(/^\/+/, '')}`;
|
||||
|
||||
rewrites.push({
|
||||
source: normalizedSource,
|
||||
destination: TRACKER_SCRIPT,
|
||||
});
|
||||
|
||||
headers.push({
|
||||
source: normalizedSource,
|
||||
headers: trackerHeaders,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (cloudMode && cloudUrl) {
|
||||
redirects.push({
|
||||
source: '/settings/:path*',
|
||||
@ -153,12 +193,7 @@ const config = {
|
||||
return config;
|
||||
},
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: '/:path*',
|
||||
headers,
|
||||
},
|
||||
];
|
||||
return headers;
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "umami",
|
||||
"version": "2.13.2",
|
||||
"version": "2.14.0",
|
||||
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
|
||||
"author": "Umami Software, Inc. <hello@umami.is>",
|
||||
"license": "MIT",
|
||||
@ -123,7 +123,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@formatjs/cli": "^4.2.29",
|
||||
"@netlify/plugin-nextjs": "^5.1.0",
|
||||
"@netlify/plugin-nextjs": "^5.8.1",
|
||||
"@rollup/plugin-alias": "^5.0.0",
|
||||
"@rollup/plugin-commonjs": "^25.0.4",
|
||||
"@rollup/plugin-json": "^6.0.0",
|
||||
|
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
||||
"label.access-code": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Access code"
|
||||
"value": "Přístupový kód"
|
||||
}
|
||||
],
|
||||
"label.actions": [
|
||||
@ -14,31 +14,31 @@
|
||||
"label.activity": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Activity log"
|
||||
"value": "Log aktivity"
|
||||
}
|
||||
],
|
||||
"label.add": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Add"
|
||||
"value": "Přidat"
|
||||
}
|
||||
],
|
||||
"label.add-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Add description"
|
||||
"value": "Přidat popis"
|
||||
}
|
||||
],
|
||||
"label.add-member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Add member"
|
||||
"value": "Přidat člena"
|
||||
}
|
||||
],
|
||||
"label.add-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Add step"
|
||||
"value": "Přidat krok"
|
||||
}
|
||||
],
|
||||
"label.add-website": [
|
||||
@ -56,7 +56,7 @@
|
||||
"label.after": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "After"
|
||||
"value": "Po"
|
||||
}
|
||||
],
|
||||
"label.all": [
|
||||
@ -68,7 +68,7 @@
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "All time"
|
||||
"value": "Celá doba"
|
||||
}
|
||||
],
|
||||
"label.analytics": [
|
||||
@ -80,7 +80,7 @@
|
||||
"label.average": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Average"
|
||||
"value": "Průměr"
|
||||
}
|
||||
],
|
||||
"label.back": [
|
||||
@ -92,7 +92,7 @@
|
||||
"label.before": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Before"
|
||||
"value": "Před"
|
||||
}
|
||||
],
|
||||
"label.bounce-rate": [
|
||||
@ -110,13 +110,13 @@
|
||||
"label.browser": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Browser"
|
||||
"value": "Prohlížeč"
|
||||
}
|
||||
],
|
||||
"label.browsers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Prohlížeč"
|
||||
"value": "Prohlížeče"
|
||||
}
|
||||
],
|
||||
"label.cancel": [
|
||||
@ -134,31 +134,31 @@
|
||||
"label.cities": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Cities"
|
||||
"value": "Města"
|
||||
}
|
||||
],
|
||||
"label.city": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "City"
|
||||
"value": "Město"
|
||||
}
|
||||
],
|
||||
"label.clear-all": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Clear all"
|
||||
"value": "Vyčistit vše"
|
||||
}
|
||||
],
|
||||
"label.compare": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Compare"
|
||||
"value": "Porovnat"
|
||||
}
|
||||
],
|
||||
"label.confirm": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Confirm"
|
||||
"value": "Potvrdit"
|
||||
}
|
||||
],
|
||||
"label.confirm-password": [
|
||||
@ -170,61 +170,61 @@
|
||||
"label.contains": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Contains"
|
||||
"value": "Obsahuje"
|
||||
}
|
||||
],
|
||||
"label.continue": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Continue"
|
||||
"value": "Pokračovat"
|
||||
}
|
||||
],
|
||||
"label.count": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Count"
|
||||
"value": "Počet"
|
||||
}
|
||||
],
|
||||
"label.countries": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Země"
|
||||
"value": "Státy"
|
||||
}
|
||||
],
|
||||
"label.country": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Country"
|
||||
"value": "Stát"
|
||||
}
|
||||
],
|
||||
"label.create": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Create"
|
||||
"value": "Vytvořit"
|
||||
}
|
||||
],
|
||||
"label.create-report": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Create report"
|
||||
"value": "Vytvořit hlášení"
|
||||
}
|
||||
],
|
||||
"label.create-team": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Create team"
|
||||
"value": "Vytvořit tým"
|
||||
}
|
||||
],
|
||||
"label.create-user": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Create user"
|
||||
"value": "Vytvořit uživatele"
|
||||
}
|
||||
],
|
||||
"label.created": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Created"
|
||||
"value": "Vytvořeno"
|
||||
}
|
||||
],
|
||||
"label.created-by": [
|
||||
@ -236,7 +236,7 @@
|
||||
"label.current": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Current"
|
||||
"value": "Aktuální"
|
||||
}
|
||||
],
|
||||
"label.current-password": [
|
||||
@ -266,7 +266,7 @@
|
||||
"label.date": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Date"
|
||||
"value": "Datum"
|
||||
}
|
||||
],
|
||||
"label.date-range": [
|
||||
@ -278,7 +278,7 @@
|
||||
"label.day": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Day"
|
||||
"value": "Den"
|
||||
}
|
||||
],
|
||||
"label.default-date-range": [
|
||||
@ -296,19 +296,19 @@
|
||||
"label.delete-report": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Delete report"
|
||||
"value": "Smazat hlášení"
|
||||
}
|
||||
],
|
||||
"label.delete-team": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Delete team"
|
||||
"value": "Smazat tým"
|
||||
}
|
||||
],
|
||||
"label.delete-user": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Delete user"
|
||||
"value": "Smazat uživatele"
|
||||
}
|
||||
],
|
||||
"label.delete-website": [
|
||||
@ -320,7 +320,7 @@
|
||||
"label.description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Description"
|
||||
"value": "Popis"
|
||||
}
|
||||
],
|
||||
"label.desktop": [
|
||||
@ -332,13 +332,13 @@
|
||||
"label.details": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Details"
|
||||
"value": "Detaily"
|
||||
}
|
||||
],
|
||||
"label.device": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Device"
|
||||
"value": "Zařízení"
|
||||
}
|
||||
],
|
||||
"label.devices": [
|
||||
@ -356,7 +356,7 @@
|
||||
"label.does-not-contain": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Does not contain"
|
||||
"value": "Neobsahuje"
|
||||
}
|
||||
],
|
||||
"label.domain": [
|
||||
@ -380,13 +380,13 @@
|
||||
"label.edit-dashboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Edit dashboard"
|
||||
"value": "Upravit dashboard"
|
||||
}
|
||||
],
|
||||
"label.edit-member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Edit member"
|
||||
"value": "Upravit člena"
|
||||
}
|
||||
],
|
||||
"label.enable-share-url": [
|
||||
@ -404,13 +404,13 @@
|
||||
"label.entry": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Entry URL"
|
||||
"value": "Vstupní URL"
|
||||
}
|
||||
],
|
||||
"label.event": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Event"
|
||||
"value": "Událost"
|
||||
}
|
||||
],
|
||||
"label.event-data": [
|
||||
@ -440,7 +440,7 @@
|
||||
"label.field": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Field"
|
||||
"value": "Pole"
|
||||
}
|
||||
],
|
||||
"label.fields": [
|
||||
@ -452,7 +452,7 @@
|
||||
"label.filter": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Filter"
|
||||
"value": "Filtr"
|
||||
}
|
||||
],
|
||||
"label.filter-combined": [
|
||||
@ -470,7 +470,7 @@
|
||||
"label.filters": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Filters"
|
||||
"value": "Filtry"
|
||||
}
|
||||
],
|
||||
"label.first-seen": [
|
||||
@ -494,13 +494,13 @@
|
||||
"label.goal": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Goal"
|
||||
"value": "Cíl"
|
||||
}
|
||||
],
|
||||
"label.goals": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Goals"
|
||||
"value": "Cíle"
|
||||
}
|
||||
],
|
||||
"label.goals-description": [
|
||||
@ -596,13 +596,13 @@
|
||||
"label.language": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Language"
|
||||
"value": "Jazyk"
|
||||
}
|
||||
],
|
||||
"label.languages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Languages"
|
||||
"value": "Jazyky"
|
||||
}
|
||||
],
|
||||
"label.laptop": [
|
||||
@ -642,7 +642,7 @@
|
||||
"label.last-months": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Last "
|
||||
"value": "Posledních "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -650,7 +650,7 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " months"
|
||||
"value": " měsíců"
|
||||
}
|
||||
],
|
||||
"label.last-seen": [
|
||||
@ -662,13 +662,13 @@
|
||||
"label.leave": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Leave"
|
||||
"value": "Opustit"
|
||||
}
|
||||
],
|
||||
"label.leave-team": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Leave team"
|
||||
"value": "Opustit tým"
|
||||
}
|
||||
],
|
||||
"label.less-than": [
|
||||
@ -698,13 +698,13 @@
|
||||
"label.manage": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Manage"
|
||||
"value": "Spravovat"
|
||||
}
|
||||
],
|
||||
"label.manager": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Manager"
|
||||
"value": "Správce"
|
||||
}
|
||||
],
|
||||
"label.max": [
|
||||
@ -716,13 +716,13 @@
|
||||
"label.member": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Member"
|
||||
"value": "Člen"
|
||||
}
|
||||
],
|
||||
"label.members": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Members"
|
||||
"value": "Členové"
|
||||
}
|
||||
],
|
||||
"label.min": [
|
||||
@ -746,13 +746,13 @@
|
||||
"label.my-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "My account"
|
||||
"value": "Můj účet"
|
||||
}
|
||||
],
|
||||
"label.my-websites": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "My websites"
|
||||
"value": "Mé weby"
|
||||
}
|
||||
],
|
||||
"label.name": [
|
||||
@ -822,13 +822,13 @@
|
||||
"label.overview": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Overview"
|
||||
"value": "Přehled"
|
||||
}
|
||||
],
|
||||
"label.owner": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Owner"
|
||||
"value": "Vlastník"
|
||||
}
|
||||
],
|
||||
"label.page-of": [
|
||||
@ -858,7 +858,7 @@
|
||||
"label.pageTitle": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Page title"
|
||||
"value": "Název stránky"
|
||||
}
|
||||
],
|
||||
"label.pages": [
|
||||
@ -876,13 +876,13 @@
|
||||
"label.path": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Path"
|
||||
"value": "Cesta"
|
||||
}
|
||||
],
|
||||
"label.paths": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Paths"
|
||||
"value": "Cesty"
|
||||
}
|
||||
],
|
||||
"label.powered-by": [
|
||||
@ -1444,13 +1444,13 @@
|
||||
"label.visitors": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Návštěvy"
|
||||
"value": "Návštěvníci"
|
||||
}
|
||||
],
|
||||
"label.visits": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visits"
|
||||
"value": "Návštěvy"
|
||||
}
|
||||
],
|
||||
"label.website": [
|
||||
@ -1474,13 +1474,13 @@
|
||||
"label.window": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Window"
|
||||
"value": "Okno"
|
||||
}
|
||||
],
|
||||
"label.yesterday": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Yesterday"
|
||||
"value": "Včera"
|
||||
}
|
||||
],
|
||||
"message.action-confirmation": [
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -410,13 +410,13 @@
|
||||
"label.event": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Ereigniss"
|
||||
"value": "Ereignis"
|
||||
}
|
||||
],
|
||||
"label.event-data": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Ereignissdaten"
|
||||
"value": "Ereignisdaten"
|
||||
}
|
||||
],
|
||||
"label.events": [
|
||||
@ -1798,7 +1798,7 @@
|
||||
"message.triggered-event": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Ausgelöstes Ereigniss"
|
||||
"value": "Ereignis ausgelöst"
|
||||
}
|
||||
],
|
||||
"message.user-deleted": [
|
||||
|
@ -404,7 +404,7 @@
|
||||
"label.entry": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Entry URL"
|
||||
"value": "URL d'entrée"
|
||||
}
|
||||
],
|
||||
"label.event": [
|
||||
@ -476,7 +476,7 @@
|
||||
"label.first-seen": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "First seen"
|
||||
"value": "Vu pour la première fois"
|
||||
}
|
||||
],
|
||||
"label.funnel": [
|
||||
@ -506,7 +506,7 @@
|
||||
"label.goals-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Track your goals for pageviews and events."
|
||||
"value": "Suivez vos objectifs en matière de pages vues et d'événements."
|
||||
}
|
||||
],
|
||||
"label.greater-than": [
|
||||
@ -590,7 +590,7 @@
|
||||
"label.journey-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Understand how users navigate through your website."
|
||||
"value": "Comprendre comment les utilisateurs naviguent sur votre site web."
|
||||
}
|
||||
],
|
||||
"label.language": [
|
||||
@ -886,19 +886,19 @@
|
||||
"label.previous": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous"
|
||||
"value": "Précédent"
|
||||
}
|
||||
],
|
||||
"label.previous-period": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous period"
|
||||
"value": "Période précédente"
|
||||
}
|
||||
],
|
||||
"label.previous-year": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous year"
|
||||
"value": "Année précédente"
|
||||
}
|
||||
],
|
||||
"label.profile": [
|
||||
@ -910,13 +910,13 @@
|
||||
"label.properties": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Properties"
|
||||
"value": "Propriétés"
|
||||
}
|
||||
],
|
||||
"label.property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Property"
|
||||
"value": "Propriété"
|
||||
}
|
||||
],
|
||||
"label.queries": [
|
||||
@ -1036,13 +1036,13 @@
|
||||
"label.revenue-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Look into your revenue across time."
|
||||
"value": "Examinez vos revenus au fil du temps."
|
||||
}
|
||||
],
|
||||
"label.revenue-property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Revenue Property"
|
||||
"value": "Propriétés des revenues"
|
||||
}
|
||||
],
|
||||
"label.role": [
|
||||
@ -1078,7 +1078,7 @@
|
||||
"label.select": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Select"
|
||||
"value": "Selectionner"
|
||||
}
|
||||
],
|
||||
"label.select-date": [
|
||||
@ -1132,7 +1132,7 @@
|
||||
"label.start-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Start Step"
|
||||
"value": "Etape de démarrage"
|
||||
}
|
||||
],
|
||||
"label.steps": [
|
||||
@ -1168,7 +1168,7 @@
|
||||
"label.team-manager": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Team manager"
|
||||
"value": "Manager de l'équipe"
|
||||
}
|
||||
],
|
||||
"label.team-member": [
|
||||
@ -1192,7 +1192,7 @@
|
||||
"label.team-view-only": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Team view only"
|
||||
"value": "Vue d'équipe uniquement"
|
||||
}
|
||||
],
|
||||
"label.team-websites": [
|
||||
@ -1318,7 +1318,7 @@
|
||||
"label.uniqueCustomers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Unique Customers"
|
||||
"value": "Clients uniques"
|
||||
}
|
||||
],
|
||||
"label.unknown": [
|
||||
@ -1360,7 +1360,7 @@
|
||||
"label.user-property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "User Property"
|
||||
"value": "Propriétés d'utilisateurs"
|
||||
}
|
||||
],
|
||||
"label.username": [
|
||||
|
@ -1012,7 +1012,7 @@
|
||||
"label.retention-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "사용자가 얼마나 자주 돌아오는지를 추적하여 웹사이트의 리텐션을 측정하십시오."
|
||||
"value": "사용자가 얼마나 자주 돌아오는지를 추적하여 웹사이트의 리텐션을 측정하세요."
|
||||
}
|
||||
],
|
||||
"label.revenue": [
|
||||
@ -1372,7 +1372,7 @@
|
||||
"label.utm-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM 매개변수를 통해 캠페인을 추적합니다."
|
||||
"value": "UTM 매개변수를 통해 캠페인을 추적하세요."
|
||||
}
|
||||
],
|
||||
"label.value": [
|
||||
@ -1414,7 +1414,7 @@
|
||||
"label.visit-duration": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "평균 방문 시간"
|
||||
"value": "방문 시간"
|
||||
}
|
||||
],
|
||||
"label.visitors": [
|
||||
@ -1548,7 +1548,7 @@
|
||||
"message.error": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "오류가 발생했습니다."
|
||||
"value": "문제가 발생했습니다."
|
||||
}
|
||||
],
|
||||
"message.event-log": [
|
||||
|
@ -38,13 +38,13 @@
|
||||
"label.add-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Add step"
|
||||
"value": "Adaugă pas"
|
||||
}
|
||||
],
|
||||
"label.add-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Adăugare site web"
|
||||
"value": "Adaugă site web"
|
||||
}
|
||||
],
|
||||
"label.admin": [
|
||||
@ -152,7 +152,7 @@
|
||||
"label.compare": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Compare"
|
||||
"value": "Compară"
|
||||
}
|
||||
],
|
||||
"label.confirm": [
|
||||
@ -182,7 +182,7 @@
|
||||
"label.count": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Count"
|
||||
"value": "Număr"
|
||||
}
|
||||
],
|
||||
"label.countries": [
|
||||
@ -230,13 +230,13 @@
|
||||
"label.created-by": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Created By"
|
||||
"value": "Creat de"
|
||||
}
|
||||
],
|
||||
"label.current": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Current"
|
||||
"value": "Curent"
|
||||
}
|
||||
],
|
||||
"label.current-password": [
|
||||
@ -266,13 +266,13 @@
|
||||
"label.date": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Data"
|
||||
"value": "Dată"
|
||||
}
|
||||
],
|
||||
"label.date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Interval de date"
|
||||
"value": "Interval"
|
||||
}
|
||||
],
|
||||
"label.day": [
|
||||
@ -284,7 +284,7 @@
|
||||
"label.default-date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Interval de date implicit"
|
||||
"value": "Interval implicit"
|
||||
}
|
||||
],
|
||||
"label.delete": [
|
||||
@ -314,7 +314,7 @@
|
||||
"label.delete-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Ștergere site web"
|
||||
"value": "Șterge site web"
|
||||
}
|
||||
],
|
||||
"label.description": [
|
||||
@ -398,13 +398,13 @@
|
||||
"label.end-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "End Step"
|
||||
"value": "Pas final"
|
||||
}
|
||||
],
|
||||
"label.entry": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Entry URL"
|
||||
"value": "URL de intrare"
|
||||
}
|
||||
],
|
||||
"label.event": [
|
||||
@ -428,7 +428,7 @@
|
||||
"label.exit": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Exit URL"
|
||||
"value": "URL de ieșire"
|
||||
}
|
||||
],
|
||||
"label.false": [
|
||||
@ -476,7 +476,7 @@
|
||||
"label.first-seen": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "First seen"
|
||||
"value": "Văzut pentru prima dată"
|
||||
}
|
||||
],
|
||||
"label.funnel": [
|
||||
@ -494,19 +494,19 @@
|
||||
"label.goal": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Goal"
|
||||
"value": "Obiectiv"
|
||||
}
|
||||
],
|
||||
"label.goals": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Goals"
|
||||
"value": "Obiective"
|
||||
}
|
||||
],
|
||||
"label.goals-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Track your goals for pageviews and events."
|
||||
"value": "Urmărește obiectivele de vizualizări și evenimente."
|
||||
}
|
||||
],
|
||||
"label.greater-than": [
|
||||
@ -584,13 +584,13 @@
|
||||
"label.journey": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Journey"
|
||||
"value": "Traseu"
|
||||
}
|
||||
],
|
||||
"label.journey-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Understand how users navigate through your website."
|
||||
"value": "Înțelege cum navighează vizitatorii prin website."
|
||||
}
|
||||
],
|
||||
"label.language": [
|
||||
@ -642,7 +642,7 @@
|
||||
"label.last-months": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Last "
|
||||
"value": "Ultimele "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
@ -650,13 +650,13 @@
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " months"
|
||||
"value": " luni"
|
||||
}
|
||||
],
|
||||
"label.last-seen": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Last seen"
|
||||
"value": "Văzut ultima dată"
|
||||
}
|
||||
],
|
||||
"label.leave": [
|
||||
@ -876,13 +876,13 @@
|
||||
"label.path": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Path"
|
||||
"value": "Rută"
|
||||
}
|
||||
],
|
||||
"label.paths": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Paths"
|
||||
"value": "Rute"
|
||||
}
|
||||
],
|
||||
"label.powered-by": [
|
||||
@ -898,19 +898,19 @@
|
||||
"label.previous": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous"
|
||||
"value": "Anterior"
|
||||
}
|
||||
],
|
||||
"label.previous-period": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous period"
|
||||
"value": "Perioda anterioară"
|
||||
}
|
||||
],
|
||||
"label.previous-year": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Previous year"
|
||||
"value": "Anul anterior"
|
||||
}
|
||||
],
|
||||
"label.profile": [
|
||||
@ -922,13 +922,13 @@
|
||||
"label.properties": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Properties"
|
||||
"value": "Proprietăți"
|
||||
}
|
||||
],
|
||||
"label.property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Property"
|
||||
"value": "Proprietate"
|
||||
}
|
||||
],
|
||||
"label.queries": [
|
||||
@ -1042,13 +1042,13 @@
|
||||
"label.revenue": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Revenue"
|
||||
"value": "Venit"
|
||||
}
|
||||
],
|
||||
"label.revenue-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Look into your revenue across time."
|
||||
"value": "Urmărește venitul în timp."
|
||||
}
|
||||
],
|
||||
"label.revenue-property": [
|
||||
@ -1114,7 +1114,7 @@
|
||||
"label.session": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Session"
|
||||
"value": "Sesiune"
|
||||
}
|
||||
],
|
||||
"label.sessions": [
|
||||
@ -1144,13 +1144,13 @@
|
||||
"label.start-step": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Start Step"
|
||||
"value": "Pas de început"
|
||||
}
|
||||
],
|
||||
"label.steps": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Steps"
|
||||
"value": "Pași"
|
||||
}
|
||||
],
|
||||
"label.sum": [
|
||||
@ -1174,13 +1174,13 @@
|
||||
"label.team-id": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ID Echipa"
|
||||
"value": "ID Echipă"
|
||||
}
|
||||
],
|
||||
"label.team-manager": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Team manager"
|
||||
"value": "Manager echipă"
|
||||
}
|
||||
],
|
||||
"label.team-member": [
|
||||
@ -1288,7 +1288,7 @@
|
||||
"label.transactions": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Transactions"
|
||||
"value": "Tranzacții"
|
||||
}
|
||||
],
|
||||
"label.transfer": [
|
||||
@ -1330,7 +1330,7 @@
|
||||
"label.uniqueCustomers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Unique Customers"
|
||||
"value": "Clienți unici"
|
||||
}
|
||||
],
|
||||
"label.unknown": [
|
||||
@ -1372,7 +1372,7 @@
|
||||
"label.user-property": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "User Property"
|
||||
"value": "Proprietatea utilizatorului"
|
||||
}
|
||||
],
|
||||
"label.username": [
|
||||
@ -1396,7 +1396,7 @@
|
||||
"label.utm-description": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Track your campaigns through UTM parameters."
|
||||
"value": "Urmărește campaniile tale cu parametri UTM."
|
||||
}
|
||||
],
|
||||
"label.value": [
|
||||
@ -1432,7 +1432,7 @@
|
||||
"label.views-per-visit": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Views per visit"
|
||||
"value": "Vizualizări per vizită"
|
||||
}
|
||||
],
|
||||
"label.visit-duration": [
|
||||
@ -1450,7 +1450,7 @@
|
||||
"label.visits": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Visits"
|
||||
"value": "Vizite"
|
||||
}
|
||||
],
|
||||
"label.website": [
|
||||
@ -1534,7 +1534,7 @@
|
||||
"message.collected-data": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Collected data"
|
||||
"value": "Date colectate"
|
||||
}
|
||||
],
|
||||
"message.confirm-delete": [
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -15,9 +15,9 @@ async function sendTelemetry(type) {
|
||||
node: process.version,
|
||||
platform: os.platform(),
|
||||
arch: os.arch(),
|
||||
os: `${os.type()} (${os.version()})`,
|
||||
isDocker: isDocker(),
|
||||
isCi: isCI,
|
||||
os: `${os.type()} ${os.version()}`,
|
||||
is_docker: isDocker(),
|
||||
is_ci: isCI,
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -10,6 +10,8 @@ import TeamsButton from 'components/input/TeamsButton';
|
||||
import Icons from 'components/icons';
|
||||
import { useMessages, useNavigation, useTeamUrl } from 'components/hooks';
|
||||
import styles from './NavBar.module.css';
|
||||
import { useEffect } from 'react';
|
||||
import { getItem, setItem } from 'next-basics';
|
||||
|
||||
export function NavBar() {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
@ -74,10 +76,26 @@ export function NavBar() {
|
||||
|
||||
const handleTeamChange = (teamId: string) => {
|
||||
const url = teamId ? `/teams/${teamId}` : '/';
|
||||
|
||||
if (!cloudMode) {
|
||||
setItem('umami.team', { id: teamId });
|
||||
}
|
||||
router.push(cloudMode ? `${process.env.cloudUrl}${url}` : url);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}, [cloudMode]);
|
||||
|
||||
return (
|
||||
<div className={styles.navbar}>
|
||||
<div className={styles.logo}>
|
||||
|
@ -48,6 +48,46 @@ export function TestConsole({ websiteId }: { websiteId: string }) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleRunRevenue() {
|
||||
window['umami'].track(props => ({
|
||||
...props,
|
||||
url: '/checkout-cart',
|
||||
referrer: 'https://www.google.com',
|
||||
}));
|
||||
window['umami'].track('checkout-cart', {
|
||||
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
|
||||
currency: 'USD',
|
||||
});
|
||||
window['umami'].track('affiliate-link', {
|
||||
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
|
||||
currency: 'USD',
|
||||
});
|
||||
window['umami'].track('promotion-link', {
|
||||
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
|
||||
currency: 'USD',
|
||||
});
|
||||
window['umami'].track('checkout-cart', {
|
||||
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
|
||||
currency: 'EUR',
|
||||
});
|
||||
window['umami'].track('promotion-link', {
|
||||
revenue: parseFloat((Math.random() * 1000).toFixed(2)),
|
||||
currency: 'EUR',
|
||||
});
|
||||
window['umami'].track('affiliate-link', {
|
||||
item1: {
|
||||
productIdentity: 'ABC424',
|
||||
revenue: parseFloat((Math.random() * 10000).toFixed(2)),
|
||||
currency: 'JPY',
|
||||
},
|
||||
item2: {
|
||||
productIdentity: 'ZYW684',
|
||||
revenue: parseFloat((Math.random() * 10000).toFixed(2)),
|
||||
currency: 'JPY',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function handleRunIdentify() {
|
||||
window['umami'].identify({
|
||||
userId: 123,
|
||||
@ -127,10 +167,19 @@ export function TestConsole({ websiteId }: { websiteId: string }) {
|
||||
>
|
||||
Send event with data
|
||||
</Button>
|
||||
<Button
|
||||
id="generate-revenue-button"
|
||||
data-umami-event="checkout-cart"
|
||||
data-umami-event-revenue={(Math.random() * 10000).toFixed(2).toString()}
|
||||
data-umami-event-currency="USD"
|
||||
variant="primary"
|
||||
>
|
||||
Generate revenue data
|
||||
</Button>
|
||||
<Button
|
||||
id="button-with-div-button"
|
||||
data-umami-event="button-click"
|
||||
data-umami-event-name="bob"
|
||||
data-umami-event-name={'bob'}
|
||||
data-umami-event-id="123"
|
||||
variant="primary"
|
||||
>
|
||||
@ -155,6 +204,9 @@ export function TestConsole({ websiteId }: { websiteId: string }) {
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunIdentify}>
|
||||
Run identify
|
||||
</Button>
|
||||
<Button id="manual-button" variant="primary" onClick={handleRunRevenue}>
|
||||
Revenue script
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<WebsiteChart websiteId={website.id} />
|
||||
|
@ -1,34 +1,34 @@
|
||||
.buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.item h1 {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.item h2 {
|
||||
font-size: 14px;
|
||||
color: var(--base700);
|
||||
}
|
||||
|
||||
.text {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid var(--base400);
|
||||
background: var(--base50);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.active .text {
|
||||
border-color: var(--base600);
|
||||
box-shadow: 4px 4px 4px var(--base100);
|
||||
.text {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.name {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.domain {
|
||||
font-size: 14px;
|
||||
color: var(--base700);
|
||||
}
|
||||
|
||||
.dragActive {
|
||||
@ -38,3 +38,20 @@
|
||||
.dragActive:active {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 20px;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.search {
|
||||
max-width: 360px;
|
||||
}
|
||||
|
||||
.active {
|
||||
border-color: var(--base600);
|
||||
box-shadow: 4px 4px 4px var(--base100);
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { useState, useMemo, useEffect } from 'react';
|
||||
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
||||
import classNames from 'classnames';
|
||||
import { Button, Loading } from 'react-basics';
|
||||
import { Button, Loading, Toggle, SearchField } from 'react-basics';
|
||||
import { firstBy } from 'thenby';
|
||||
import useDashboard, { saveDashboard } from 'store/dashboard';
|
||||
import { useMessages, useWebsites } from 'components/hooks';
|
||||
@ -11,20 +11,39 @@ const DRAG_ID = 'dashboard-website-ordering';
|
||||
|
||||
export function DashboardEdit({ teamId }: { teamId: string }) {
|
||||
const settings = useDashboard();
|
||||
const { websiteOrder } = settings;
|
||||
const { websiteOrder, websiteActive, isEdited } = settings;
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const [order, setOrder] = useState(websiteOrder || []);
|
||||
const [active, setActive] = useState(websiteActive || []);
|
||||
const [edited, setEdited] = useState(isEdited);
|
||||
const [websites, setWebsites] = useState([]);
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
const {
|
||||
result,
|
||||
query: { isLoading },
|
||||
setParams,
|
||||
} = useWebsites({ teamId });
|
||||
|
||||
const websites = result?.data;
|
||||
useEffect(() => {
|
||||
if (result?.data) {
|
||||
setWebsites(prevWebsites => {
|
||||
const newWebsites = [...prevWebsites, ...result.data];
|
||||
if (newWebsites.length < result.count) {
|
||||
setParams(prevParams => ({ ...prevParams, page: prevParams.page + 1 }));
|
||||
}
|
||||
return newWebsites;
|
||||
});
|
||||
}
|
||||
}, [result]);
|
||||
|
||||
const ordered = useMemo(() => {
|
||||
if (websites) {
|
||||
return websites
|
||||
.map((website: { id: any }) => ({ ...website, order: order.indexOf(website.id) }))
|
||||
.map((website: { id: any; name: string; domain: string }) => ({
|
||||
...website,
|
||||
order: order.indexOf(website.id),
|
||||
}))
|
||||
.sort(firstBy('order'));
|
||||
}
|
||||
return [];
|
||||
@ -38,21 +57,33 @@ export function DashboardEdit({ teamId }: { teamId: string }) {
|
||||
orderedWebsites.splice(destination.index, 0, removed);
|
||||
|
||||
setOrder(orderedWebsites.map(website => website?.id || 0));
|
||||
setEdited(true);
|
||||
}
|
||||
|
||||
function handleActiveWebsites(id: string) {
|
||||
setActive(prevActive =>
|
||||
prevActive.includes(id) ? prevActive.filter(a => a !== id) : [...prevActive, id],
|
||||
);
|
||||
setEdited(true);
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
saveDashboard({
|
||||
editing: false,
|
||||
isEdited: edited,
|
||||
websiteOrder: order,
|
||||
websiteActive: active,
|
||||
});
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
saveDashboard({ editing: false, websiteOrder });
|
||||
saveDashboard({ editing: false, websiteOrder, websiteActive, isEdited });
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
setOrder([]);
|
||||
setActive([]);
|
||||
setEdited(false);
|
||||
}
|
||||
|
||||
if (isLoading) {
|
||||
@ -61,16 +92,19 @@ export function DashboardEdit({ teamId }: { teamId: string }) {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.buttons}>
|
||||
<Button onClick={handleSave} variant="primary" size="sm">
|
||||
{formatMessage(labels.save)}
|
||||
</Button>
|
||||
<Button onClick={handleCancel} size="sm">
|
||||
{formatMessage(labels.cancel)}
|
||||
</Button>
|
||||
<Button onClick={handleReset} size="sm">
|
||||
{formatMessage(labels.reset)}
|
||||
</Button>
|
||||
<div className={styles.header}>
|
||||
<SearchField className={styles.search} value={search} onSearch={setSearch} />
|
||||
<div className={styles.buttons}>
|
||||
<Button onClick={handleSave} variant="primary" size="sm">
|
||||
{formatMessage(labels.save)}
|
||||
</Button>
|
||||
<Button onClick={handleCancel} size="sm">
|
||||
{formatMessage(labels.cancel)}
|
||||
</Button>
|
||||
<Button onClick={handleReset} size="sm">
|
||||
{formatMessage(labels.reset)}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.dragActive}>
|
||||
<DragDropContext onDragEnd={handleWebsiteDrag}>
|
||||
@ -81,25 +115,38 @@ export function DashboardEdit({ teamId }: { teamId: string }) {
|
||||
ref={provided.innerRef}
|
||||
style={{ marginBottom: snapshot.isDraggingOver ? 260 : null }}
|
||||
>
|
||||
{ordered.map(({ id, name, domain }, index) => (
|
||||
<Draggable key={id} draggableId={`${DRAG_ID}-${id}`} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
className={classNames(styles.item, {
|
||||
[styles.active]: snapshot.isDragging,
|
||||
})}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
>
|
||||
<div className={styles.text}>
|
||||
<h1>{name}</h1>
|
||||
<h2>{domain}</h2>
|
||||
{ordered.map(({ id, name, domain }, index) => {
|
||||
if (
|
||||
search &&
|
||||
!`${name.toLowerCase()}${domain.toLowerCase()}`.includes(search.toLowerCase())
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Draggable key={id} draggableId={`${DRAG_ID}-${id}`} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
className={classNames(styles.item, {
|
||||
[styles.active]: snapshot.isDragging,
|
||||
})}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
>
|
||||
<div className={styles.text}>
|
||||
<div className={styles.name}>{name}</div>
|
||||
<div className={styles.domain}>{domain}</div>
|
||||
</div>
|
||||
<Toggle
|
||||
checked={active.includes(id)}
|
||||
onChange={() => handleActiveWebsites(id)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
)}
|
||||
</Draggable>
|
||||
);
|
||||
})}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
|
@ -13,9 +13,9 @@ import LinkButton from 'components/common/LinkButton';
|
||||
export function DashboardPage() {
|
||||
const { formatMessage, labels, messages } = useMessages();
|
||||
const { teamId, renderTeamUrl } = useTeamUrl();
|
||||
const { showCharts, editing } = useDashboard();
|
||||
const { showCharts, editing, isEdited } = useDashboard();
|
||||
const { dir } = useLocale();
|
||||
const pageSize = 10;
|
||||
const pageSize = isEdited ? 200 : 10;
|
||||
|
||||
const { result, query, params, setParams } = useWebsites({ teamId }, { pageSize });
|
||||
const { page } = params;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Funnel from 'assets/funnel.svg';
|
||||
import Money from 'assets/money.svg';
|
||||
import Lightbulb from 'assets/lightbulb.svg';
|
||||
import Magnet from 'assets/magnet.svg';
|
||||
import Path from 'assets/path.svg';
|
||||
@ -51,12 +52,12 @@ export function ReportTemplates({ showHeader = true }: { showHeader?: boolean })
|
||||
url: renderTeamUrl('/reports/journey'),
|
||||
icon: <Path />,
|
||||
},
|
||||
// {
|
||||
// title: formatMessage(labels.revenue),
|
||||
// description: formatMessage(labels.revenueDescription),
|
||||
// url: renderTeamUrl('/reports/revenue'),
|
||||
// icon: <Money />,
|
||||
// },
|
||||
{
|
||||
title: formatMessage(labels.revenue),
|
||||
description: formatMessage(labels.revenueDescription),
|
||||
url: renderTeamUrl('/reports/revenue'),
|
||||
icon: <Money />,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
|
@ -1,98 +0,0 @@
|
||||
import BarChart, { BarChartProps } from 'components/charts/BarChart';
|
||||
import { useLocale, useMessages } from 'components/hooks';
|
||||
import MetricCard from 'components/metrics/MetricCard';
|
||||
import MetricsBar from 'components/metrics/MetricsBar';
|
||||
import { renderDateLabels } from 'lib/charts';
|
||||
import { formatLongNumber } from 'lib/format';
|
||||
import { useContext, useMemo } from 'react';
|
||||
import { ReportContext } from '../[reportId]/Report';
|
||||
|
||||
export interface PageviewsChartProps extends BarChartProps {
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export function RevenueChart({ isLoading, ...props }: PageviewsChartProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { locale } = useLocale();
|
||||
const { report } = useContext(ReportContext);
|
||||
const { data, parameters } = report || {};
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
if (!data) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
datasets: [
|
||||
{
|
||||
label: formatMessage(labels.average),
|
||||
data: data?.chart.map(a => ({ x: a.time, y: a.avg })),
|
||||
borderWidth: 2,
|
||||
backgroundColor: '#8601B0',
|
||||
borderColor: '#8601B0',
|
||||
order: 1,
|
||||
},
|
||||
{
|
||||
label: formatMessage(labels.total),
|
||||
data: data?.chart.map(a => ({ x: a.time, y: a.sum })),
|
||||
borderWidth: 2,
|
||||
backgroundColor: '#f15bb5',
|
||||
borderColor: '#f15bb5',
|
||||
order: 2,
|
||||
},
|
||||
],
|
||||
};
|
||||
}, [data, locale]);
|
||||
|
||||
const metricData = useMemo(() => {
|
||||
if (!data) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const { sum, avg, count, uniqueCount } = data.total;
|
||||
|
||||
return [
|
||||
{
|
||||
value: sum,
|
||||
label: formatMessage(labels.total),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: avg,
|
||||
label: formatMessage(labels.average),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: count,
|
||||
label: formatMessage(labels.transactions),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: uniqueCount,
|
||||
label: formatMessage(labels.uniqueCustomers),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
] as any;
|
||||
}, [data, locale]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<MetricsBar isFetched={data}>
|
||||
{metricData?.map(({ label, value, formatValue }) => {
|
||||
return <MetricCard key={label} value={value} label={label} formatValue={formatValue} />;
|
||||
})}
|
||||
</MetricsBar>
|
||||
{data && (
|
||||
<BarChart
|
||||
{...props}
|
||||
data={chartData}
|
||||
unit={parameters?.dateRange.unit}
|
||||
isLoading={isLoading}
|
||||
renderXLabel={renderDateLabels(parameters?.dateRange.unit, locale)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default RevenueChart;
|
@ -1,46 +1,41 @@
|
||||
import { useMessages } from 'components/hooks';
|
||||
import useRevenueValues from 'components/hooks/queries/useRevenueValues';
|
||||
import { useContext } from 'react';
|
||||
import { Form, FormButtons, FormInput, FormRow, SubmitButton, TextField } from 'react-basics';
|
||||
import { Dropdown, Form, FormButtons, FormInput, FormRow, Item, SubmitButton } from 'react-basics';
|
||||
import BaseParameters from '../[reportId]/BaseParameters';
|
||||
import { ReportContext } from '../[reportId]/Report';
|
||||
|
||||
export function RevenueParameters() {
|
||||
const { report, runReport, isRunning } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const { id, parameters } = report || {};
|
||||
const { websiteId, dateRange } = parameters || {};
|
||||
const queryDisabled = !websiteId || !dateRange;
|
||||
const queryEnabled = websiteId && dateRange;
|
||||
const { data: values = [] } = useRevenueValues(
|
||||
websiteId,
|
||||
dateRange?.startDate,
|
||||
dateRange?.endDate,
|
||||
);
|
||||
|
||||
const handleSubmit = (data: any, e: any) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
if (!queryDisabled) {
|
||||
runReport(data);
|
||||
}
|
||||
runReport(data);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form values={parameters} onSubmit={handleSubmit} preventSubmit={true}>
|
||||
<BaseParameters showDateSelect={true} allowWebsiteSelect={!id} />
|
||||
<FormRow label={formatMessage(labels.event)}>
|
||||
<FormInput name="eventName" rules={{ required: formatMessage(labels.required) }}>
|
||||
<TextField autoComplete="off" />
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormRow label={formatMessage(labels.revenueProperty)}>
|
||||
<FormInput name="revenueProperty" rules={{ required: formatMessage(labels.required) }}>
|
||||
<TextField autoComplete="off" />
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormRow label={formatMessage(labels.userProperty)}>
|
||||
<FormInput name="userProperty">
|
||||
<TextField autoComplete="off" />
|
||||
<FormRow label={formatMessage(labels.currency)}>
|
||||
<FormInput name="currency" rules={{ required: formatMessage(labels.required) }}>
|
||||
<Dropdown items={values.map(item => item.currency)}>
|
||||
{item => <Item key={item}>{item}</Item>}
|
||||
</Dropdown>
|
||||
</FormInput>
|
||||
</FormRow>
|
||||
<FormButtons>
|
||||
<SubmitButton variant="primary" disabled={queryDisabled} isLoading={isRunning}>
|
||||
<SubmitButton variant="primary" disabled={!queryEnabled} isLoading={isRunning}>
|
||||
{formatMessage(labels.runQuery)}
|
||||
</SubmitButton>
|
||||
</FormButtons>
|
||||
|
@ -1,10 +0,0 @@
|
||||
.filters {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
border: 1px solid var(--base400);
|
||||
border-radius: var(--border-radius);
|
||||
line-height: 32px;
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
}
|
@ -1,15 +1,15 @@
|
||||
import RevenueChart from './RevenueChart';
|
||||
import RevenueParameters from './RevenueParameters';
|
||||
import Report from '../[reportId]/Report';
|
||||
import ReportHeader from '../[reportId]/ReportHeader';
|
||||
import ReportMenu from '../[reportId]/ReportMenu';
|
||||
import ReportBody from '../[reportId]/ReportBody';
|
||||
import Money from 'assets/money.svg';
|
||||
import { REPORT_TYPES } from 'lib/constants';
|
||||
import Report from '../[reportId]/Report';
|
||||
import ReportBody from '../[reportId]/ReportBody';
|
||||
import ReportHeader from '../[reportId]/ReportHeader';
|
||||
import ReportMenu from '../[reportId]/ReportMenu';
|
||||
import RevenueParameters from './RevenueParameters';
|
||||
import RevenueView from './RevenueView';
|
||||
|
||||
const defaultParameters = {
|
||||
type: REPORT_TYPES.revenue,
|
||||
parameters: { Revenue: [] },
|
||||
parameters: {},
|
||||
};
|
||||
|
||||
export default function RevenueReport({ reportId }: { reportId?: string }) {
|
||||
@ -20,7 +20,7 @@ export default function RevenueReport({ reportId }: { reportId?: string }) {
|
||||
<RevenueParameters />
|
||||
</ReportMenu>
|
||||
<ReportBody>
|
||||
<RevenueChart unit="day" />
|
||||
<RevenueView />
|
||||
</ReportBody>
|
||||
</Report>
|
||||
);
|
||||
|
38
src/app/(main)/reports/revenue/RevenueTable.tsx
Normal file
38
src/app/(main)/reports/revenue/RevenueTable.tsx
Normal file
@ -0,0 +1,38 @@
|
||||
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { useContext } from 'react';
|
||||
import { GridColumn, GridTable } from 'react-basics';
|
||||
import { ReportContext } from '../[reportId]/Report';
|
||||
import { formatLongCurrency } from 'lib/format';
|
||||
|
||||
export function RevenueTable() {
|
||||
const { report } = useContext(ReportContext);
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { data } = report || {};
|
||||
|
||||
if (!data) {
|
||||
return <EmptyPlaceholder />;
|
||||
}
|
||||
|
||||
return (
|
||||
<GridTable data={data.table || []}>
|
||||
<GridColumn name="currency" label={formatMessage(labels.currency)} alignment="end">
|
||||
{row => row.currency}
|
||||
</GridColumn>
|
||||
<GridColumn name="currency" label={formatMessage(labels.total)} width="300px" alignment="end">
|
||||
{row => formatLongCurrency(row.sum, row.currency)}
|
||||
</GridColumn>
|
||||
<GridColumn name="currency" label={formatMessage(labels.average)} alignment="end">
|
||||
{row => formatLongCurrency(row.count ? row.sum / row.count : 0, row.currency)}
|
||||
</GridColumn>
|
||||
<GridColumn name="currency" label={formatMessage(labels.transactions)} alignment="end">
|
||||
{row => row.count}
|
||||
</GridColumn>
|
||||
<GridColumn name="currency" label={formatMessage(labels.uniqueCustomers)} alignment="end">
|
||||
{row => row.unique_count}
|
||||
</GridColumn>
|
||||
</GridTable>
|
||||
);
|
||||
}
|
||||
|
||||
export default RevenueTable;
|
11
src/app/(main)/reports/revenue/RevenueView.module.css
Normal file
11
src/app/(main)/reports/revenue/RevenueView.module.css
Normal file
@ -0,0 +1,11 @@
|
||||
.container {
|
||||
display: grid;
|
||||
gap: 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
156
src/app/(main)/reports/revenue/RevenueView.tsx
Normal file
156
src/app/(main)/reports/revenue/RevenueView.tsx
Normal file
@ -0,0 +1,156 @@
|
||||
import classNames from 'classnames';
|
||||
import { colord } from 'colord';
|
||||
import BarChart from 'components/charts/BarChart';
|
||||
import PieChart from 'components/charts/PieChart';
|
||||
import TypeIcon from 'components/common/TypeIcon';
|
||||
import { useCountryNames, useLocale, useMessages } from 'components/hooks';
|
||||
import { GridRow } from 'components/layout/Grid';
|
||||
import ListTable from 'components/metrics/ListTable';
|
||||
import MetricCard from 'components/metrics/MetricCard';
|
||||
import MetricsBar from 'components/metrics/MetricsBar';
|
||||
import { renderDateLabels } from 'lib/charts';
|
||||
import { CHART_COLORS } from 'lib/constants';
|
||||
import { formatLongCurrency, formatLongNumber } from 'lib/format';
|
||||
import { useCallback, useContext, useMemo } from 'react';
|
||||
import { ReportContext } from '../[reportId]/Report';
|
||||
import RevenueTable from './RevenueTable';
|
||||
import styles from './RevenueView.module.css';
|
||||
|
||||
export interface RevenueViewProps {
|
||||
isLoading?: boolean;
|
||||
}
|
||||
|
||||
export function RevenueView({ isLoading }: RevenueViewProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { locale } = useLocale();
|
||||
const { countryNames } = useCountryNames(locale);
|
||||
const { report } = useContext(ReportContext);
|
||||
const {
|
||||
data,
|
||||
parameters: { dateRange, currency },
|
||||
} = report || {};
|
||||
const showTable = data?.table.length > 1;
|
||||
|
||||
const renderCountryName = useCallback(
|
||||
({ x: code }) => (
|
||||
<span className={classNames(locale, styles.row)}>
|
||||
<TypeIcon type="country" value={code?.toLowerCase()} />
|
||||
{countryNames[code]}
|
||||
</span>
|
||||
),
|
||||
[countryNames, locale],
|
||||
);
|
||||
|
||||
const chartData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
const map = (data.chart as any[]).reduce((obj, { x, t, y }) => {
|
||||
if (!obj[x]) {
|
||||
obj[x] = [];
|
||||
}
|
||||
|
||||
obj[x].push({ x: t, y });
|
||||
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
return {
|
||||
datasets: Object.keys(map).map((key, index) => {
|
||||
const color = colord(CHART_COLORS[index % CHART_COLORS.length]);
|
||||
return {
|
||||
label: key,
|
||||
data: map[key],
|
||||
lineTension: 0,
|
||||
backgroundColor: color.alpha(0.6).toRgbString(),
|
||||
borderColor: color.alpha(0.7).toRgbString(),
|
||||
borderWidth: 1,
|
||||
};
|
||||
}),
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
const countryData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
const labels = data.country.map(({ name }) => name);
|
||||
const datasets = [
|
||||
{
|
||||
data: data.country.map(({ value }) => value),
|
||||
backgroundColor: CHART_COLORS,
|
||||
borderWidth: 0,
|
||||
},
|
||||
];
|
||||
|
||||
return { labels, datasets };
|
||||
}, [data]);
|
||||
|
||||
const metricData = useMemo(() => {
|
||||
if (!data) return [];
|
||||
|
||||
const { sum, count, unique_count } = data.total;
|
||||
|
||||
return [
|
||||
{
|
||||
value: sum,
|
||||
label: formatMessage(labels.total),
|
||||
formatValue: n => formatLongCurrency(n, currency),
|
||||
},
|
||||
{
|
||||
value: count ? sum / count : 0,
|
||||
label: formatMessage(labels.average),
|
||||
formatValue: n => formatLongCurrency(n, currency),
|
||||
},
|
||||
{
|
||||
value: count,
|
||||
label: formatMessage(labels.transactions),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
{
|
||||
value: unique_count,
|
||||
label: formatMessage(labels.uniqueCustomers),
|
||||
formatValue: formatLongNumber,
|
||||
},
|
||||
] as any;
|
||||
}, [data, locale]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.container}>
|
||||
<MetricsBar isFetched={data}>
|
||||
{metricData?.map(({ label, value, formatValue }) => {
|
||||
return <MetricCard key={label} value={value} label={label} formatValue={formatValue} />;
|
||||
})}
|
||||
</MetricsBar>
|
||||
{data && (
|
||||
<>
|
||||
<BarChart
|
||||
minDate={dateRange?.startDate}
|
||||
maxDate={dateRange?.endDate}
|
||||
data={chartData}
|
||||
unit={dateRange?.unit}
|
||||
stacked={true}
|
||||
currency={currency}
|
||||
renderXLabel={renderDateLabels(dateRange?.unit, locale)}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
<GridRow columns="two">
|
||||
<ListTable
|
||||
metric={formatMessage(labels.country)}
|
||||
data={data?.country.map(({ name, value }) => ({
|
||||
x: name,
|
||||
y: Number(value),
|
||||
z: (value / data?.total.sum) * 100,
|
||||
}))}
|
||||
renderLabel={renderCountryName}
|
||||
/>
|
||||
<PieChart type="doughnut" data={countryData} />
|
||||
</GridRow>
|
||||
</>
|
||||
)}
|
||||
{showTable && <RevenueTable />}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default RevenueView;
|
@ -18,17 +18,16 @@ export default function WebsiteChartList({
|
||||
limit?: number;
|
||||
}) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { websiteOrder } = useDashboard();
|
||||
const { websiteOrder, websiteActive } = useDashboard();
|
||||
const { renderTeamUrl } = useTeamUrl();
|
||||
const { dir } = useLocale();
|
||||
|
||||
const ordered = useMemo(
|
||||
() =>
|
||||
websites
|
||||
.map(website => ({ ...website, order: websiteOrder.indexOf(website.id) || 0 }))
|
||||
.sort(firstBy('order')),
|
||||
[websites, websiteOrder],
|
||||
);
|
||||
const ordered = useMemo(() => {
|
||||
return websites
|
||||
.filter(website => (websiteActive.length ? websiteActive.includes(website.id) : true))
|
||||
.map(website => ({ ...website, order: websiteOrder.indexOf(website.id) || 0 }))
|
||||
.sort(firstBy('order'));
|
||||
}, [websites, websiteOrder, websiteActive]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
@ -59,5 +59,6 @@
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-inline-end: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,21 @@
|
||||
import { Icons, Icon, Text, Dropdown, Item } from 'react-basics';
|
||||
import LinkButton from 'components/common/LinkButton';
|
||||
import { useLocale, useMessages, useNavigation } from 'components/hooks';
|
||||
import SideNav from 'components/layout/SideNav';
|
||||
import BrowsersTable from 'components/metrics/BrowsersTable';
|
||||
import CountriesTable from 'components/metrics/CountriesTable';
|
||||
import RegionsTable from 'components/metrics/RegionsTable';
|
||||
import CitiesTable from 'components/metrics/CitiesTable';
|
||||
import CountriesTable from 'components/metrics/CountriesTable';
|
||||
import DevicesTable from 'components/metrics/DevicesTable';
|
||||
import EventsTable from 'components/metrics/EventsTable';
|
||||
import HostsTable from 'components/metrics/HostsTable';
|
||||
import LanguagesTable from 'components/metrics/LanguagesTable';
|
||||
import OSTable from 'components/metrics/OSTable';
|
||||
import PagesTable from 'components/metrics/PagesTable';
|
||||
import QueryParametersTable from 'components/metrics/QueryParametersTable';
|
||||
import ReferrersTable from 'components/metrics/ReferrersTable';
|
||||
import HostsTable from 'components/metrics/HostsTable';
|
||||
import RegionsTable from 'components/metrics/RegionsTable';
|
||||
import ScreenTable from 'components/metrics/ScreenTable';
|
||||
import EventsTable from 'components/metrics/EventsTable';
|
||||
import SideNav from 'components/layout/SideNav';
|
||||
import { useNavigation, useMessages, useLocale } from 'components/hooks';
|
||||
import LinkButton from 'components/common/LinkButton';
|
||||
import TagsTable from 'components/metrics/TagsTable';
|
||||
import { Dropdown, Icon, Icons, Item, Text } from 'react-basics';
|
||||
import styles from './WebsiteExpandedView.module.css';
|
||||
|
||||
const views = {
|
||||
@ -34,6 +35,7 @@ const views = {
|
||||
language: LanguagesTable,
|
||||
event: EventsTable,
|
||||
query: QueryParametersTable,
|
||||
tag: TagsTable,
|
||||
};
|
||||
|
||||
export default function WebsiteExpandedView({
|
||||
@ -117,6 +119,11 @@ export default function WebsiteExpandedView({
|
||||
label: formatMessage(labels.hosts),
|
||||
url: renderUrl({ view: 'host' }),
|
||||
},
|
||||
{
|
||||
key: 'tag',
|
||||
label: formatMessage(labels.tags),
|
||||
url: renderUrl({ view: 'tag' }),
|
||||
},
|
||||
];
|
||||
|
||||
const DetailsComponent = views[view] || (() => null);
|
||||
|
@ -1,24 +1,25 @@
|
||||
import { useState } from 'react';
|
||||
import SideNav from 'components/layout/SideNav';
|
||||
import { useDateRange, useMessages, useNavigation } from 'components/hooks';
|
||||
import PagesTable from 'components/metrics/PagesTable';
|
||||
import ReferrersTable from 'components/metrics/ReferrersTable';
|
||||
import BrowsersTable from 'components/metrics/BrowsersTable';
|
||||
import OSTable from 'components/metrics/OSTable';
|
||||
import DevicesTable from 'components/metrics/DevicesTable';
|
||||
import ScreenTable from 'components/metrics/ScreenTable';
|
||||
import CountriesTable from 'components/metrics/CountriesTable';
|
||||
import RegionsTable from 'components/metrics/RegionsTable';
|
||||
import CitiesTable from 'components/metrics/CitiesTable';
|
||||
import LanguagesTable from 'components/metrics/LanguagesTable';
|
||||
import EventsTable from 'components/metrics/EventsTable';
|
||||
import QueryParametersTable from 'components/metrics/QueryParametersTable';
|
||||
import { Grid, GridRow } from 'components/layout/Grid';
|
||||
import SideNav from 'components/layout/SideNav';
|
||||
import BrowsersTable from 'components/metrics/BrowsersTable';
|
||||
import ChangeLabel from 'components/metrics/ChangeLabel';
|
||||
import CitiesTable from 'components/metrics/CitiesTable';
|
||||
import CountriesTable from 'components/metrics/CountriesTable';
|
||||
import DevicesTable from 'components/metrics/DevicesTable';
|
||||
import EventsTable from 'components/metrics/EventsTable';
|
||||
import LanguagesTable from 'components/metrics/LanguagesTable';
|
||||
import MetricsTable from 'components/metrics/MetricsTable';
|
||||
import useStore from 'store/websites';
|
||||
import OSTable from 'components/metrics/OSTable';
|
||||
import PagesTable from 'components/metrics/PagesTable';
|
||||
import QueryParametersTable from 'components/metrics/QueryParametersTable';
|
||||
import ReferrersTable from 'components/metrics/ReferrersTable';
|
||||
import RegionsTable from 'components/metrics/RegionsTable';
|
||||
import ScreenTable from 'components/metrics/ScreenTable';
|
||||
import TagsTable from 'components/metrics/TagsTable';
|
||||
import { getCompareDate } from 'lib/date';
|
||||
import { formatNumber } from 'lib/format';
|
||||
import ChangeLabel from 'components/metrics/ChangeLabel';
|
||||
import { useState } from 'react';
|
||||
import useStore from 'store/websites';
|
||||
import styles from './WebsiteCompareTables.module.css';
|
||||
|
||||
const views = {
|
||||
@ -35,6 +36,7 @@ const views = {
|
||||
language: LanguagesTable,
|
||||
event: EventsTable,
|
||||
query: QueryParametersTable,
|
||||
tag: TagsTable,
|
||||
};
|
||||
|
||||
export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
|
||||
@ -109,6 +111,16 @@ export function WebsiteCompareTables({ websiteId }: { websiteId: string }) {
|
||||
label: formatMessage(labels.queryParameters),
|
||||
url: renderUrl({ view: 'query' }),
|
||||
},
|
||||
{
|
||||
key: 'host',
|
||||
label: formatMessage(labels.hosts),
|
||||
url: renderUrl({ view: 'host' }),
|
||||
},
|
||||
{
|
||||
key: 'tag',
|
||||
label: formatMessage(labels.tags),
|
||||
url: renderUrl({ view: 'tag' }),
|
||||
},
|
||||
];
|
||||
|
||||
const renderChange = ({ x, y }) => {
|
||||
|
@ -54,7 +54,7 @@ export function EventProperties({ websiteId }: { websiteId: string }) {
|
||||
{propertyName && (
|
||||
<div className={styles.chart}>
|
||||
<div className={styles.title}>{propertyName}</div>
|
||||
<PieChart key={propertyName} type="doughnut" data={chartData} />
|
||||
<PieChart key={propertyName + eventName} type="doughnut" data={chartData} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
@ -12,7 +12,7 @@ export function RealtimeCountries({ data }) {
|
||||
|
||||
const renderCountryName = useCallback(
|
||||
({ x: code }) => (
|
||||
<span className={classNames(locale, styles.row)}>
|
||||
<span className={classNames(styles.row)}>
|
||||
<TypeIcon type="country" value={code?.toLowerCase()} />
|
||||
{countryNames[code]}
|
||||
</span>
|
||||
|
@ -4,7 +4,6 @@ import '@fontsource/inter/400.css';
|
||||
import '@fontsource/inter/700.css';
|
||||
import '@fontsource/inter/800.css';
|
||||
import 'react-basics/dist/styles.css';
|
||||
import 'styles/locale.css';
|
||||
import 'styles/index.css';
|
||||
import 'styles/variables.css';
|
||||
|
||||
|
8
src/assets/pushpin.svg
Normal file
8
src/assets/pushpin.svg
Normal file
@ -0,0 +1,8 @@
|
||||
<svg
|
||||
viewBox="0 0 1024 1024"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
width="1em"
|
||||
>
|
||||
<path d="M878.3 392.1L631.9 145.7c-6.5-6.5-15-9.7-23.5-9.7s-17 3.2-23.5 9.7L423.8 306.9c-12.2-1.4-24.5-2-36.8-2-73.2 0-146.4 24.1-206.5 72.3-15.4 12.3-16.6 35.4-2.7 49.4l181.7 181.7-215.4 215.2a15.8 15.8 0 00-4.6 9.8l-3.4 37.2c-.9 9.4 6.6 17.4 15.9 17.4.5 0 1 0 1.5-.1l37.2-3.4c3.7-.3 7.2-2 9.8-4.6l215.4-215.4 181.7 181.7c6.5 6.5 15 9.7 23.5 9.7 9.7 0 19.3-4.2 25.9-12.4 56.3-70.3 79.7-158.3 70.2-243.4l161.1-161.1c12.9-12.8 12.9-33.8 0-46.8z" />
|
||||
</svg>
|
After Width: | Height: | Size: 571 B |
@ -7,6 +7,7 @@ import { useMemo, useState } from 'react';
|
||||
export interface BarChartProps extends ChartProps {
|
||||
unit: string;
|
||||
stacked?: boolean;
|
||||
currency?: string;
|
||||
renderXLabel?: (label: string, index: number, values: any[]) => string;
|
||||
renderYLabel?: (label: string, index: number, values: any[]) => string;
|
||||
XAxisType?: string;
|
||||
@ -27,6 +28,7 @@ export function BarChart(props: BarChartProps) {
|
||||
stacked = false,
|
||||
minDate,
|
||||
maxDate,
|
||||
currency,
|
||||
} = props;
|
||||
|
||||
const options: any = useMemo(() => {
|
||||
@ -76,7 +78,9 @@ export function BarChart(props: BarChartProps) {
|
||||
const handleTooltip = ({ tooltip }: { tooltip: any }) => {
|
||||
const { opacity } = tooltip;
|
||||
|
||||
setTooltip(opacity ? <BarChartTooltip tooltip={tooltip} unit={unit} /> : null);
|
||||
setTooltip(
|
||||
opacity ? <BarChartTooltip tooltip={tooltip} unit={unit} currency={currency} /> : null,
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { formatDate } from 'lib/date';
|
||||
import { Flexbox, StatusLight } from 'react-basics';
|
||||
import { formatLongNumber } from 'lib/format';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import { formatDate } from 'lib/date';
|
||||
import { formatLongCurrency, formatLongNumber } from 'lib/format';
|
||||
import { Flexbox, StatusLight } from 'react-basics';
|
||||
|
||||
const formats = {
|
||||
millisecond: 'T',
|
||||
@ -15,7 +15,7 @@ const formats = {
|
||||
year: 'yyyy',
|
||||
};
|
||||
|
||||
export default function BarChartTooltip({ tooltip, unit }) {
|
||||
export default function BarChartTooltip({ tooltip, unit, currency }) {
|
||||
const { locale } = useLocale();
|
||||
const { labelColors, dataPoints } = tooltip;
|
||||
|
||||
@ -26,7 +26,10 @@ export default function BarChartTooltip({ tooltip, unit }) {
|
||||
</div>
|
||||
<div>
|
||||
<StatusLight color={labelColors?.[0]?.backgroundColor}>
|
||||
{formatLongNumber(dataPoints[0].raw.y)} {dataPoints[0].dataset.label}
|
||||
{currency
|
||||
? formatLongCurrency(dataPoints[0].raw.y, currency)
|
||||
: formatLongNumber(dataPoints[0].raw.y)}{' '}
|
||||
{dataPoints[0].dataset.label}
|
||||
</StatusLight>
|
||||
</div>
|
||||
</Flexbox>
|
||||
|
@ -1,9 +1,7 @@
|
||||
export * from './queries/useApi';
|
||||
export * from './queries/useConfig';
|
||||
export * from './queries/useEventDataEvents';
|
||||
export * from './queries/useEventDataProperties';
|
||||
export * from './queries/useEventDataValues';
|
||||
export * from './queries/usePagedQuery';
|
||||
export * from './queries/useLogin';
|
||||
export * from './queries/useRealtime';
|
||||
export * from './queries/useReport';
|
||||
@ -28,6 +26,7 @@ export * from './queries/useWebsiteEvents';
|
||||
export * from './queries/useWebsiteEventsSeries';
|
||||
export * from './queries/useWebsiteMetrics';
|
||||
export * from './queries/useWebsiteValues';
|
||||
export * from './useApi';
|
||||
export * from './useCountryNames';
|
||||
export * from './useDateRange';
|
||||
export * from './useDocumentClick';
|
||||
@ -41,6 +40,7 @@ export * from './useLocale';
|
||||
export * from './useMessages';
|
||||
export * from './useModified';
|
||||
export * from './useNavigation';
|
||||
export * from './usePagedQuery';
|
||||
export * from './useRegionNames';
|
||||
export * from './useSticky';
|
||||
export * from './useTeamUrl';
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import useStore, { setConfig } from 'store/app';
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
let loading = false;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useApi from './useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
export function useEventDataProperties(
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useApi from './useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
export function useEventDataValues(
|
||||
@ -12,7 +12,7 @@ export function useEventDataValues(
|
||||
const params = useFilterParams(websiteId);
|
||||
|
||||
return useQuery<any>({
|
||||
queryKey: ['websites:event-data:values', { websiteId, propertyName, ...params }],
|
||||
queryKey: ['websites:event-data:values', { websiteId, eventName, propertyName, ...params }],
|
||||
queryFn: () =>
|
||||
get(`/websites/${websiteId}/event-data/values`, { ...params, eventName, propertyName }),
|
||||
enabled: !!(websiteId && propertyName),
|
||||
|
@ -1,6 +1,6 @@
|
||||
import useStore, { setUser } from 'store/app';
|
||||
import useApi from './useApi';
|
||||
import { UseQueryResult } from '@tanstack/react-query';
|
||||
import useStore, { setUser } from 'store/app';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
const selector = (state: { user: any }) => state.user;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { useTimezone } from 'components/hooks';
|
||||
import { REALTIME_INTERVAL } from 'lib/constants';
|
||||
import { RealtimeData } from 'lib/types';
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useRealtime(websiteId: string) {
|
||||
const { get, useQuery } = useApi();
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { produce } from 'immer';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { useTimezone } from '../useTimezone';
|
||||
import { useMessages } from '../useMessages';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useApi from './useApi';
|
||||
import usePagedQuery from './usePagedQuery';
|
||||
import useApi from '../useApi';
|
||||
import usePagedQuery from '../usePagedQuery';
|
||||
import useModified from '../useModified';
|
||||
|
||||
export function useReports({ websiteId, teamId }: { websiteId?: string; teamId?: string }) {
|
||||
|
18
src/components/hooks/queries/useRevenueValues.ts
Normal file
18
src/components/hooks/queries/useRevenueValues.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useRevenueValues(websiteId: string, startDate: Date, endDate: Date) {
|
||||
const { get, useQuery } = useApi();
|
||||
|
||||
return useQuery({
|
||||
queryKey: ['revenue:values', { websiteId, startDate, endDate }],
|
||||
queryFn: () =>
|
||||
get(`/reports/revenue`, {
|
||||
websiteId,
|
||||
startDate,
|
||||
endDate,
|
||||
}),
|
||||
enabled: !!(websiteId && startDate && endDate),
|
||||
});
|
||||
}
|
||||
|
||||
export default useRevenueValues;
|
@ -1,4 +1,4 @@
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useSessionActivity(
|
||||
websiteId: string,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useSessionData(websiteId: string, sessionId: string) {
|
||||
const { get, useQuery } = useApi();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useStore, { setShareToken } from 'store/app';
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
const selector = (state: { shareToken: string }) => state.shareToken;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useTeam(teamId: string) {
|
||||
const { get, useQuery } = useApi();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useApi from './useApi';
|
||||
import usePagedQuery from './usePagedQuery';
|
||||
import { useApi } from '../useApi';
|
||||
import usePagedQuery from '../usePagedQuery';
|
||||
import useModified from '../useModified';
|
||||
|
||||
export function useTeamMembers(teamId: string) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useApi from './useApi';
|
||||
import usePagedQuery from './usePagedQuery';
|
||||
import { useApi } from '../useApi';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
import useModified from '../useModified';
|
||||
|
||||
export function useTeamWebsites(teamId: string) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useApi from './useApi';
|
||||
import usePagedQuery from './usePagedQuery';
|
||||
import { useApi } from '../useApi';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
import useModified from '../useModified';
|
||||
|
||||
export function useTeams(userId: string) {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useUser(userId: string, options?: { [key: string]: any }) {
|
||||
const { get, useQuery } = useApi();
|
||||
|
@ -1,5 +1,5 @@
|
||||
import useApi from './useApi';
|
||||
import usePagedQuery from './usePagedQuery';
|
||||
import { useApi } from '../useApi';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
import useModified from '../useModified';
|
||||
|
||||
export function useUsers() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useWebsite(websiteId: string, options?: { [key: string]: any }) {
|
||||
const { get, useQuery } = useApi();
|
||||
|
@ -1,7 +1,7 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
import { usePagedQuery } from './usePagedQuery';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
|
||||
export function useWebsiteEvents(
|
||||
websiteId: string,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import useApi from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
|
||||
export function useWebsiteMetrics(
|
||||
websiteId: string,
|
||||
@ -9,6 +10,7 @@ export function useWebsiteMetrics(
|
||||
) {
|
||||
const { get, useQuery } = useApi();
|
||||
const params = useFilterParams(websiteId);
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
return useQuery({
|
||||
queryKey: [
|
||||
@ -20,12 +22,9 @@ export function useWebsiteMetrics(
|
||||
},
|
||||
],
|
||||
queryFn: async () => {
|
||||
const filters = { ...params };
|
||||
|
||||
filters[queryParams.type] = undefined;
|
||||
|
||||
const data = await get(`/websites/${websiteId}/metrics`, {
|
||||
...filters,
|
||||
...params,
|
||||
[searchParams.get('view')]: undefined,
|
||||
...queryParams,
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParams } from '..//useFilterParams';
|
||||
|
||||
export function useWebsitePageviews(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useWebsiteSession(websiteId: string, sessionId: string) {
|
||||
const { get, useQuery } = useApi();
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
export function useWebsiteSessionStats(websiteId: string, options?: { [key: string]: string }) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useApi } from './useApi';
|
||||
import { usePagedQuery } from './usePagedQuery';
|
||||
import { useApi } from '../useApi';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
import useModified from '../useModified';
|
||||
import { useFilterParams } from 'components/hooks/useFilterParams';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import useModified from '../useModified';
|
||||
import { useFilterParams } from 'components/hooks/useFilterParams';
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
import { useFilterParams } from '../useFilterParams';
|
||||
|
||||
export function useWebsiteStats(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useApi } from './useApi';
|
||||
import { useApi } from '../useApi';
|
||||
|
||||
export function useWebsiteValues({
|
||||
websiteId,
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useApi } from './useApi';
|
||||
import { usePagedQuery } from './usePagedQuery';
|
||||
import { useApi } from '../useApi';
|
||||
import { usePagedQuery } from '../usePagedQuery';
|
||||
import { useLogin } from './useLogin';
|
||||
import useModified from '../useModified';
|
||||
|
||||
|
@ -5,7 +5,7 @@ import websiteStore, { setWebsiteDateRange, setWebsiteDateCompare } from 'store/
|
||||
import appStore, { setDateRange } from 'store/app';
|
||||
import { DateRange } from 'lib/types';
|
||||
import { useLocale } from './useLocale';
|
||||
import { useApi } from './queries/useApi';
|
||||
import { useApi } from './useApi';
|
||||
|
||||
export function useDateRange(websiteId?: string): {
|
||||
dateRange: DateRange;
|
||||
|
@ -15,6 +15,7 @@ export function useFields() {
|
||||
{ name: 'region', type: 'string', label: formatMessage(labels.region) },
|
||||
{ name: 'city', type: 'string', label: formatMessage(labels.city) },
|
||||
{ name: 'host', type: 'string', label: formatMessage(labels.host) },
|
||||
{ name: 'tag', type: 'string', label: formatMessage(labels.tag) },
|
||||
];
|
||||
|
||||
return { fields };
|
||||
|
@ -7,7 +7,21 @@ export function useFilterParams(websiteId: string) {
|
||||
const { startDate, endDate, unit } = dateRange;
|
||||
const { timezone, toUtc } = useTimezone();
|
||||
const {
|
||||
query: { url, referrer, title, query, host, os, browser, device, country, region, city, event },
|
||||
query: {
|
||||
url,
|
||||
referrer,
|
||||
title,
|
||||
query,
|
||||
host,
|
||||
os,
|
||||
browser,
|
||||
device,
|
||||
country,
|
||||
region,
|
||||
city,
|
||||
event,
|
||||
tag,
|
||||
},
|
||||
} = useNavigation();
|
||||
|
||||
return {
|
||||
@ -27,5 +41,6 @@ export function useFilterParams(websiteId: string) {
|
||||
region,
|
||||
city,
|
||||
event,
|
||||
tag,
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { UseQueryOptions } from '@tanstack/react-query';
|
||||
import { useState } from 'react';
|
||||
import { useApi } from './useApi';
|
||||
import { PageResult, PageParams, PagedQueryResult } from 'lib/types';
|
||||
import { useNavigation } from '../useNavigation';
|
||||
import { useApi } from './useApi';
|
||||
import { useNavigation } from './useNavigation';
|
||||
|
||||
export function usePagedQuery<T = any>({
|
||||
queryKey,
|
@ -19,6 +19,7 @@ import Moon from 'assets/moon.svg';
|
||||
import Nodes from 'assets/nodes.svg';
|
||||
import Overview from 'assets/overview.svg';
|
||||
import Profile from 'assets/profile.svg';
|
||||
import PushPin from 'assets/pushpin.svg';
|
||||
import Reports from 'assets/reports.svg';
|
||||
import Sun from 'assets/sun.svg';
|
||||
import User from 'assets/user.svg';
|
||||
@ -47,6 +48,7 @@ const icons = {
|
||||
Nodes,
|
||||
Overview,
|
||||
Profile,
|
||||
PushPin,
|
||||
Reports,
|
||||
Sun,
|
||||
User,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { Icon, Button, PopupTrigger, Popup, Text } from 'react-basics';
|
||||
import { Icon, Button, PopupTrigger, Popup } from 'react-basics';
|
||||
import classNames from 'classnames';
|
||||
import { languages } from 'lib/lang';
|
||||
import { useLocale } from 'components/hooks';
|
||||
@ -33,7 +33,7 @@ export function LanguageButton() {
|
||||
className={classNames(styles.item, { [styles.selected]: value === locale })}
|
||||
onClick={(e: any) => handleSelect(value, close, e)}
|
||||
>
|
||||
<Text>{label}</Text>
|
||||
<span lang={value}>{label}</span>
|
||||
{value === locale && (
|
||||
<Icon className={styles.icon}>
|
||||
<Icons.Check />
|
||||
|
@ -98,6 +98,7 @@ export const labels = defineMessages({
|
||||
devices: { id: 'label.devices', defaultMessage: 'Devices' },
|
||||
countries: { id: 'label.countries', defaultMessage: 'Countries' },
|
||||
languages: { id: 'label.languages', defaultMessage: 'Languages' },
|
||||
tags: { id: 'label.tags', defaultMessage: 'Tags' },
|
||||
count: { id: 'label.count', defaultMessage: 'Count' },
|
||||
average: { id: 'label.average', defaultMessage: 'Average' },
|
||||
sum: { id: 'label.sum', defaultMessage: 'Sum' },
|
||||
@ -114,8 +115,6 @@ export const labels = defineMessages({
|
||||
none: { id: 'label.none', defaultMessage: 'None' },
|
||||
clearAll: { id: 'label.clear-all', defaultMessage: 'Clear all' },
|
||||
property: { id: 'label.property', defaultMessage: 'Property' },
|
||||
revenueProperty: { id: 'label.revenue-property', defaultMessage: 'Revenue Property' },
|
||||
userProperty: { id: 'label.user-property', defaultMessage: 'User Property' },
|
||||
today: { id: 'label.today', defaultMessage: 'Today' },
|
||||
lastHours: { id: 'label.last-hours', defaultMessage: 'Last {x} hours' },
|
||||
yesterday: { id: 'label.yesterday', defaultMessage: 'Yesterday' },
|
||||
@ -153,6 +152,7 @@ export const labels = defineMessages({
|
||||
regions: { id: 'label.regions', defaultMessage: 'Regions' },
|
||||
reports: { id: 'label.reports', defaultMessage: 'Reports' },
|
||||
eventData: { id: 'label.event-data', defaultMessage: 'Event data' },
|
||||
sessionData: { id: 'label.session-data', defaultMessage: 'Session data' },
|
||||
funnel: { id: 'label.funnel', defaultMessage: 'Funnel' },
|
||||
funnelDescription: {
|
||||
id: 'label.funnel-description',
|
||||
@ -161,8 +161,9 @@ export const labels = defineMessages({
|
||||
revenue: { id: 'label.revenue', defaultMessage: 'Revenue' },
|
||||
revenueDescription: {
|
||||
id: 'label.revenue-description',
|
||||
defaultMessage: 'Look into your revenue across time.',
|
||||
defaultMessage: 'Look into your revenue data and how users are spending.',
|
||||
},
|
||||
currency: { id: 'label.currency', defaultMessage: 'Currency' },
|
||||
url: { id: 'label.url', defaultMessage: 'URL' },
|
||||
urls: { id: 'label.urls', defaultMessage: 'URLs' },
|
||||
path: { id: 'label.path', defaultMessage: 'Path' },
|
||||
@ -220,6 +221,7 @@ export const labels = defineMessages({
|
||||
browser: { id: 'label.browser', defaultMessage: 'Browser' },
|
||||
device: { id: 'label.device', defaultMessage: 'Device' },
|
||||
pageTitle: { id: 'label.pageTitle', defaultMessage: 'Page title' },
|
||||
tag: { id: 'label.tag', defaultMessage: 'Tag' },
|
||||
day: { id: 'label.day', defaultMessage: 'Day' },
|
||||
date: { id: 'label.date', defaultMessage: 'Date' },
|
||||
pageOf: { id: 'label.page-of', defaultMessage: 'Page {current} of {total}' },
|
||||
|
@ -12,12 +12,7 @@ export function CountriesTable({ ...props }: MetricsTableProps) {
|
||||
|
||||
const renderLink = ({ x: code }) => {
|
||||
return (
|
||||
<FilterLink
|
||||
id="country"
|
||||
className={locale}
|
||||
value={countryNames[code] && code}
|
||||
label={formatCountry(code)}
|
||||
>
|
||||
<FilterLink id="country" value={countryNames[code] && code} label={formatCountry(code)}>
|
||||
<TypeIcon type="country" value={code?.toLowerCase()} />
|
||||
</FilterLink>
|
||||
);
|
||||
|
@ -25,7 +25,7 @@ export function HostsTable(props: MetricsTableProps) {
|
||||
{...props}
|
||||
title={formatMessage(labels.hosts)}
|
||||
type="host"
|
||||
metric={formatMessage(labels.views)}
|
||||
metric={formatMessage(labels.visitors)}
|
||||
renderLabel={renderLink}
|
||||
/>
|
||||
</>
|
||||
|
@ -13,7 +13,7 @@ export function LanguagesTable({
|
||||
const languageNames = useLanguageNames(locale);
|
||||
|
||||
const renderLabel = ({ x }) => {
|
||||
return <div className={locale}>{languageNames[x?.split('-')[0]] ?? x}</div>;
|
||||
return languageNames[x?.split('-')[0]] ?? x;
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -3,7 +3,6 @@ import { safeDecodeURIComponent } from 'next-basics';
|
||||
import { colord } from 'colord';
|
||||
import classNames from 'classnames';
|
||||
import { LegendItem } from 'chart.js/auto';
|
||||
import { useLocale } from 'components/hooks';
|
||||
import styles from './Legend.module.css';
|
||||
|
||||
export function Legend({
|
||||
@ -13,8 +12,6 @@ export function Legend({
|
||||
items: any[];
|
||||
onClick: (index: LegendItem) => void;
|
||||
}) {
|
||||
const { locale } = useLocale();
|
||||
|
||||
if (!items.find(({ text }) => text)) {
|
||||
return null;
|
||||
}
|
||||
@ -32,7 +29,7 @@ export function Legend({
|
||||
onClick={() => onClick(item)}
|
||||
>
|
||||
<StatusLight color={color.alpha(color.alpha() + 0.2).toHex()}>
|
||||
<span className={locale}>{safeDecodeURIComponent(text)}</span>
|
||||
{safeDecodeURIComponent(text)}
|
||||
</StatusLight>
|
||||
</div>
|
||||
);
|
||||
|
@ -11,7 +11,7 @@ export function RegionsTable(props: MetricsTableProps) {
|
||||
|
||||
const renderLink = ({ x: code, country }) => {
|
||||
return (
|
||||
<FilterLink id="region" className={locale} value={code} label={getRegionName(code, country)}>
|
||||
<FilterLink id="region" value={code} label={getRegionName(code, country)}>
|
||||
<TypeIcon type="country" value={country?.toLowerCase()} />
|
||||
</FilterLink>
|
||||
);
|
||||
|
30
src/components/metrics/TagsTable.tsx
Normal file
30
src/components/metrics/TagsTable.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import MetricsTable, { MetricsTableProps } from './MetricsTable';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import { Flexbox } from 'react-basics';
|
||||
|
||||
export function TagsTable(props: MetricsTableProps) {
|
||||
const { formatMessage, labels } = useMessages();
|
||||
|
||||
const renderLink = ({ x: tag }) => {
|
||||
return (
|
||||
<Flexbox alignItems="center">
|
||||
<FilterLink id="tag" value={tag} label={!tag && formatMessage(labels.none)} />
|
||||
</Flexbox>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<MetricsTable
|
||||
{...props}
|
||||
title={formatMessage(labels.tags)}
|
||||
type="tag"
|
||||
metric={formatMessage(labels.views)}
|
||||
renderLabel={renderLink}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default TagsTable;
|
@ -28,6 +28,7 @@ export function WorldMap({
|
||||
const { formatMessage, labels } = useMessages();
|
||||
const { countryNames } = useCountryNames(locale);
|
||||
const visitorsLabel = formatMessage(labels.visitors).toLocaleLowerCase(locale);
|
||||
const unknownLabel = formatMessage(labels.unknown);
|
||||
const {
|
||||
dateRange: { startDate, endDate },
|
||||
} = useDateRange(websiteId);
|
||||
@ -62,7 +63,9 @@ export function WorldMap({
|
||||
if (code === 'AQ') return;
|
||||
const country = metrics?.find(({ x }) => x === code);
|
||||
setTooltipPopup(
|
||||
`${countryNames[code]}: ${formatLongNumber(country?.y || 0)} ${visitorsLabel}` as any,
|
||||
`${countryNames[code] || unknownLabel}: ${formatLongNumber(
|
||||
country?.y || 0,
|
||||
)} ${visitorsLabel}` as any,
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -1,88 +1,88 @@
|
||||
{
|
||||
"label.access-code": "Access code",
|
||||
"label.access-code": "Přístupový kód",
|
||||
"label.actions": "Akce",
|
||||
"label.activity": "Activity log",
|
||||
"label.add": "Add",
|
||||
"label.add-description": "Add description",
|
||||
"label.add-member": "Add member",
|
||||
"label.add-step": "Add step",
|
||||
"label.activity": "Log aktivity",
|
||||
"label.add": "Přidat",
|
||||
"label.add-description": "Přidat popis",
|
||||
"label.add-member": "Přidat člena",
|
||||
"label.add-step": "Přidat krok",
|
||||
"label.add-website": "Přidat web",
|
||||
"label.admin": "Administrátor",
|
||||
"label.after": "After",
|
||||
"label.after": "Po",
|
||||
"label.all": "Vše",
|
||||
"label.all-time": "All time",
|
||||
"label.all-time": "Celá doba",
|
||||
"label.analytics": "Analytics",
|
||||
"label.average": "Average",
|
||||
"label.average": "Průměr",
|
||||
"label.back": "Zpět",
|
||||
"label.before": "Before",
|
||||
"label.before": "Před",
|
||||
"label.bounce-rate": "Okamžité opuštění",
|
||||
"label.breakdown": "Breakdown",
|
||||
"label.browser": "Browser",
|
||||
"label.browsers": "Prohlížeč",
|
||||
"label.browser": "Prohlížeč",
|
||||
"label.browsers": "Prohlížeče",
|
||||
"label.cancel": "Zrušit",
|
||||
"label.change-password": "Změnit heslo",
|
||||
"label.cities": "Cities",
|
||||
"label.city": "City",
|
||||
"label.clear-all": "Clear all",
|
||||
"label.compare": "Compare",
|
||||
"label.confirm": "Confirm",
|
||||
"label.cities": "Města",
|
||||
"label.city": "Město",
|
||||
"label.clear-all": "Vyčistit vše",
|
||||
"label.compare": "Porovnat",
|
||||
"label.confirm": "Potvrdit",
|
||||
"label.confirm-password": "Potvrdit heslo",
|
||||
"label.contains": "Contains",
|
||||
"label.continue": "Continue",
|
||||
"label.count": "Count",
|
||||
"label.countries": "Země",
|
||||
"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.contains": "Obsahuje",
|
||||
"label.continue": "Pokračovat",
|
||||
"label.count": "Počet",
|
||||
"label.countries": "Státy",
|
||||
"label.country": "Stát",
|
||||
"label.create": "Vytvořit",
|
||||
"label.create-report": "Vytvořit hlášení",
|
||||
"label.create-team": "Vytvořit tým",
|
||||
"label.create-user": "Vytvořit uživatele",
|
||||
"label.created": "Vytvořeno",
|
||||
"label.created-by": "Created By",
|
||||
"label.current": "Current",
|
||||
"label.current": "Aktuální",
|
||||
"label.current-password": "Aktuální heslo",
|
||||
"label.custom-range": "Vlastní rozsah",
|
||||
"label.dashboard": "Přehled",
|
||||
"label.data": "Data",
|
||||
"label.date": "Date",
|
||||
"label.date": "Datum",
|
||||
"label.date-range": "Období",
|
||||
"label.day": "Day",
|
||||
"label.day": "Den",
|
||||
"label.default-date-range": "Výchozí období",
|
||||
"label.delete": "Smazat",
|
||||
"label.delete-report": "Delete report",
|
||||
"label.delete-team": "Delete team",
|
||||
"label.delete-user": "Delete user",
|
||||
"label.delete-report": "Smazat hlášení",
|
||||
"label.delete-team": "Smazat tým",
|
||||
"label.delete-user": "Smazat uživatele",
|
||||
"label.delete-website": "Smazat web",
|
||||
"label.description": "Description",
|
||||
"label.description": "Popis",
|
||||
"label.desktop": "Stolní počítač",
|
||||
"label.details": "Details",
|
||||
"label.device": "Device",
|
||||
"label.details": "Detaily",
|
||||
"label.device": "Zařízení",
|
||||
"label.devices": "Zařízení",
|
||||
"label.dismiss": "Odejít",
|
||||
"label.does-not-contain": "Does not contain",
|
||||
"label.does-not-contain": "Neobsahuje",
|
||||
"label.domain": "Doména",
|
||||
"label.dropoff": "Dropoff",
|
||||
"label.edit": "Upravit",
|
||||
"label.edit-dashboard": "Edit dashboard",
|
||||
"label.edit-member": "Edit member",
|
||||
"label.edit-dashboard": "Upravit dashboard",
|
||||
"label.edit-member": "Upravit člena",
|
||||
"label.enable-share-url": "Povolit sdílení URL",
|
||||
"label.end-step": "End Step",
|
||||
"label.entry": "Entry URL",
|
||||
"label.event": "Event",
|
||||
"label.entry": "Vstupní URL",
|
||||
"label.event": "Událost",
|
||||
"label.event-data": "Event data",
|
||||
"label.events": "Události",
|
||||
"label.exit": "Exit URL",
|
||||
"label.false": "False",
|
||||
"label.field": "Field",
|
||||
"label.field": "Pole",
|
||||
"label.fields": "Fields",
|
||||
"label.filter": "Filter",
|
||||
"label.filter": "Filtr",
|
||||
"label.filter-combined": "Kombinace",
|
||||
"label.filter-raw": "Nezpracované",
|
||||
"label.filters": "Filters",
|
||||
"label.filters": "Filtry",
|
||||
"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.goal": "Cíl",
|
||||
"label.goals": "Cíle",
|
||||
"label.goals-description": "Track your goals for pageviews and events.",
|
||||
"label.greater-than": "Greater than",
|
||||
"label.greater-than-equals": "Greater than or equals",
|
||||
@ -98,44 +98,44 @@
|
||||
"label.join-team": "Join team",
|
||||
"label.journey": "Journey",
|
||||
"label.journey-description": "Understand how users navigate through your website.",
|
||||
"label.language": "Language",
|
||||
"label.languages": "Languages",
|
||||
"label.language": "Jazyk",
|
||||
"label.languages": "Jazyky",
|
||||
"label.laptop": "Přenosný počítač",
|
||||
"label.last-days": "Posledních {x} dnů",
|
||||
"label.last-hours": "Posledních {x} hodin",
|
||||
"label.last-months": "Last {x} months",
|
||||
"label.last-months": "Posledních {x} měsíců",
|
||||
"label.last-seen": "Last seen",
|
||||
"label.leave": "Leave",
|
||||
"label.leave-team": "Leave team",
|
||||
"label.leave": "Opustit",
|
||||
"label.leave-team": "Opustit tým",
|
||||
"label.less-than": "Less than",
|
||||
"label.less-than-equals": "Less than or equals",
|
||||
"label.login": "Přihlásit",
|
||||
"label.logout": "Odhlásit",
|
||||
"label.manage": "Manage",
|
||||
"label.manager": "Manager",
|
||||
"label.manage": "Spravovat",
|
||||
"label.manager": "Správce",
|
||||
"label.max": "Max",
|
||||
"label.member": "Member",
|
||||
"label.members": "Members",
|
||||
"label.member": "Člen",
|
||||
"label.members": "Členové",
|
||||
"label.min": "Min",
|
||||
"label.mobile": "Mobilní telefon",
|
||||
"label.more": "Více",
|
||||
"label.my-account": "My account",
|
||||
"label.my-websites": "My websites",
|
||||
"label.my-account": "Můj účet",
|
||||
"label.my-websites": "Mé weby",
|
||||
"label.name": "Jméno",
|
||||
"label.new-password": "Nové heslo",
|
||||
"label.none": "None",
|
||||
"label.number-of-records": "{x} {x, plural, one {record} other {records}}",
|
||||
"label.ok": "OK",
|
||||
"label.os": "OS",
|
||||
"label.overview": "Overview",
|
||||
"label.owner": "Owner",
|
||||
"label.overview": "Přehled",
|
||||
"label.owner": "Vlastník",
|
||||
"label.page-of": "Page {current} of {total}",
|
||||
"label.page-views": "Zobrazení stránek",
|
||||
"label.pageTitle": "Page title",
|
||||
"label.pageTitle": "Název stránky",
|
||||
"label.pages": "Stránky",
|
||||
"label.password": "Heslo",
|
||||
"label.path": "Path",
|
||||
"label.paths": "Paths",
|
||||
"label.path": "Cesta",
|
||||
"label.paths": "Cesty",
|
||||
"label.powered-by": "Běží na {name}",
|
||||
"label.previous": "Previous",
|
||||
"label.previous-period": "Previous period",
|
||||
@ -228,13 +228,13 @@
|
||||
"label.views": "Zobrazení",
|
||||
"label.views-per-visit": "Views per visit",
|
||||
"label.visit-duration": "Průměrný čas návštěvy",
|
||||
"label.visitors": "Návštěvy",
|
||||
"label.visits": "Visits",
|
||||
"label.visitors": "Návštěvníci",
|
||||
"label.visits": "Návštěvy",
|
||||
"label.website": "Website",
|
||||
"label.website-id": "Website ID",
|
||||
"label.websites": "Weby",
|
||||
"label.window": "Window",
|
||||
"label.yesterday": "Yesterday",
|
||||
"label.window": "Okno",
|
||||
"label.yesterday": "Včera",
|
||||
"message.action-confirmation": "Type {confirmation} in the box below to confirm.",
|
||||
"message.active-users": "{x} aktuálně {x, plural, one {návštěvník} other {návštěvníci}}",
|
||||
"message.collected-data": "Collected data",
|
||||
|
@ -2,278 +2,278 @@
|
||||
"label.access-code": "Zuegangscode",
|
||||
"label.actions": "Aktione",
|
||||
"label.activity": "Aktivitätsverlauf",
|
||||
"label.add": "Add",
|
||||
"label.add-description": "Add description",
|
||||
"label.add-member": "Add member",
|
||||
"label.add-step": "Add step",
|
||||
"label.add": "hinzuefüege",
|
||||
"label.add-description": "Beschriibig hinzuefüege",
|
||||
"label.add-member": "Mitglied hinzuefüege",
|
||||
"label.add-step": "Schritt hinzuefüege",
|
||||
"label.add-website": "Websiite hinzuefüege",
|
||||
"label.admin": "Administrator",
|
||||
"label.after": "After",
|
||||
"label.after": "Nach",
|
||||
"label.all": "Alli",
|
||||
"label.all-time": "Gesamte Zitruum",
|
||||
"label.all-time": "Gsamte Zitruum",
|
||||
"label.analytics": "Analytics",
|
||||
"label.average": "Average",
|
||||
"label.average": "Durchschnitt",
|
||||
"label.back": "Zrugg",
|
||||
"label.before": "Before",
|
||||
"label.before": "Vor",
|
||||
"label.bounce-rate": "Absprungsrate",
|
||||
"label.breakdown": "Breakdown",
|
||||
"label.breakdown": "Uufschlüsselig",
|
||||
"label.browser": "Browser",
|
||||
"label.browsers": "Browser",
|
||||
"label.cancel": "Abbreche",
|
||||
"label.change-password": "Passwort ändere",
|
||||
"label.cities": "Städt",
|
||||
"label.city": "City",
|
||||
"label.city": "Stadt",
|
||||
"label.clear-all": "Alles lösche",
|
||||
"label.compare": "Compare",
|
||||
"label.compare": "Vergliiche",
|
||||
"label.confirm": "Bestätige",
|
||||
"label.confirm-password": "Passwort widerhole",
|
||||
"label.contains": "Contains",
|
||||
"label.contains": "Enthaltet",
|
||||
"label.continue": "Wiiter",
|
||||
"label.count": "Count",
|
||||
"label.count": "Azahl",
|
||||
"label.countries": "Länder",
|
||||
"label.country": "Country",
|
||||
"label.create": "Create",
|
||||
"label.create-report": "Create report",
|
||||
"label.country": "Land",
|
||||
"label.create": "Erstelle",
|
||||
"label.create-report": "Bricht erstelle",
|
||||
"label.create-team": "Team erstelle",
|
||||
"label.create-user": "Benutzer erstelle",
|
||||
"label.created": "Erstellt",
|
||||
"label.created-by": "Created By",
|
||||
"label.current": "Current",
|
||||
"label.current-password": "Jetzigs Passwort",
|
||||
"label.current": "Aktuell",
|
||||
"label.current-password": "Aktuells Passwort",
|
||||
"label.custom-range": "Benutzerdefinierte Bereich",
|
||||
"label.dashboard": "Übersicht",
|
||||
"label.data": "Datä",
|
||||
"label.date": "Date",
|
||||
"label.date": "Datum",
|
||||
"label.date-range": "Datumsbereich",
|
||||
"label.day": "Day",
|
||||
"label.default-date-range": "Vorigstellte Datumsbereich",
|
||||
"label.day": "Tag",
|
||||
"label.default-date-range": "Voriigstellte Datumsbereich",
|
||||
"label.delete": "Lösche",
|
||||
"label.delete-report": "Delete report",
|
||||
"label.delete-report": "Bricht lösche",
|
||||
"label.delete-team": "Team lösche",
|
||||
"label.delete-user": "Benutzer lösche",
|
||||
"label.delete-website": "Websiite lösche",
|
||||
"label.description": "Description",
|
||||
"label.description": "Beschriibig",
|
||||
"label.desktop": "Desktop",
|
||||
"label.details": "Details",
|
||||
"label.device": "Device",
|
||||
"label.device": "Grät",
|
||||
"label.devices": "Grät",
|
||||
"label.dismiss": "Verwerfe",
|
||||
"label.does-not-contain": "Does not contain",
|
||||
"label.dismiss": "Verwärfe",
|
||||
"label.does-not-contain": "Enthaltet nid",
|
||||
"label.domain": "Domain",
|
||||
"label.dropoff": "Dropoff",
|
||||
"label.dropoff": "Absprung",
|
||||
"label.edit": "Bearbeite",
|
||||
"label.edit-dashboard": "Dashboard bearbeite",
|
||||
"label.edit-member": "Edit member",
|
||||
"label.edit-member": "Mitglied bearbeite",
|
||||
"label.enable-share-url": "Freigab-URL aktiviere",
|
||||
"label.end-step": "End Step",
|
||||
"label.entry": "Entry URL",
|
||||
"label.event": "Event",
|
||||
"label.event-data": "Event data",
|
||||
"label.end-step": "Schlussschritt",
|
||||
"label.entry": "Iigangs URL",
|
||||
"label.event": "Ereigniss",
|
||||
"label.event-data": "Ereigniss Date",
|
||||
"label.events": "Ereigniss",
|
||||
"label.exit": "Exit URL",
|
||||
"label.false": "False",
|
||||
"label.field": "Field",
|
||||
"label.fields": "Fields",
|
||||
"label.exit": "Uusgangs URL",
|
||||
"label.false": "Falsch",
|
||||
"label.field": "Fäld",
|
||||
"label.fields": "Fälder",
|
||||
"label.filter": "Filter",
|
||||
"label.filter-combined": "Kombiniert",
|
||||
"label.filter-raw": "Rohdate",
|
||||
"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.first-seen": "Erstmal gse",
|
||||
"label.funnel": "Tunnel",
|
||||
"label.funnel-description": "Verstönd Sie d Konversions- und Abspruungsrate vo Nutzer.",
|
||||
"label.goal": "Ziel",
|
||||
"label.goals": "Ziele",
|
||||
"label.goals-description": "verfolged Sie Ihri Ziel für Siitenufrüef und Ereigniss.",
|
||||
"label.greater-than": "Grösser als",
|
||||
"label.greater-than-equals": "Grösser oder gliich",
|
||||
"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.insights": "Iiblick",
|
||||
"label.insights-description": "Vertüfed Sie sich i Ihri Date, mit Hilf vo Segment und Filter.",
|
||||
"label.is": "Isch",
|
||||
"label.is-not": "Isch nid",
|
||||
"label.is-not-set": "Isch ned gsetzt",
|
||||
"label.is-set": "Isch gsetzt",
|
||||
"label.join": "Biträte",
|
||||
"label.join-team": "Team biträte",
|
||||
"label.journey": "Journey",
|
||||
"label.journey-description": "Understand how users navigate through your website.",
|
||||
"label.journey": "Reis",
|
||||
"label.journey-description": "Verstönd Sie, wie Nutzer dur Ihri Website navigiered.",
|
||||
"label.language": "Sprach",
|
||||
"label.languages": "Sprache",
|
||||
"label.laptop": "Laptop",
|
||||
"label.last-days": "Letzti {x} Täg",
|
||||
"label.last-hours": "Letzti {x} Stunde",
|
||||
"label.last-months": "Last {x} months",
|
||||
"label.last-seen": "Last seen",
|
||||
"label.last-months": "Letzti {x} Mönet",
|
||||
"label.last-seen": "Zletzt gse",
|
||||
"label.leave": "Verlah",
|
||||
"label.leave-team": "Team verlah",
|
||||
"label.less-than": "Less than",
|
||||
"label.less-than-equals": "Less than or equals",
|
||||
"label.login": "Aamelde",
|
||||
"label.logout": "Abmelde",
|
||||
"label.manage": "Manage",
|
||||
"label.less-than": "Kliiner als",
|
||||
"label.less-than-equals": "Kliiner oder gliich",
|
||||
"label.login": "Aamälde",
|
||||
"label.logout": "Abmälde",
|
||||
"label.manage": "Verwalte",
|
||||
"label.manager": "Manager",
|
||||
"label.max": "Max",
|
||||
"label.member": "Member",
|
||||
"label.member": "Mitglied",
|
||||
"label.members": "Mitglieder",
|
||||
"label.min": "Min",
|
||||
"label.mobile": "Handy",
|
||||
"label.mobile": "Händy",
|
||||
"label.more": "Meh",
|
||||
"label.my-account": "My account",
|
||||
"label.my-websites": "My websites",
|
||||
"label.my-account": "Min Account",
|
||||
"label.my-websites": "Mini Websiite",
|
||||
"label.name": "Name",
|
||||
"label.new-password": "Neus Passwort",
|
||||
"label.none": "Keis",
|
||||
"label.number-of-records": "{x} {x, plural, one {record} other {records}}",
|
||||
"label.ok": "OK",
|
||||
"label.os": "OS",
|
||||
"label.overview": "Overview",
|
||||
"label.overview": "Übersicht",
|
||||
"label.owner": "Bsitzer",
|
||||
"label.page-of": "Page {current} of {total}",
|
||||
"label.page-of": "Siite {current} vo {total}",
|
||||
"label.page-views": "Siitenufrüef",
|
||||
"label.pageTitle": "Page title",
|
||||
"label.pageTitle": "Siitetitel",
|
||||
"label.pages": "Siite",
|
||||
"label.password": "Passwort",
|
||||
"label.path": "Path",
|
||||
"label.paths": "Paths",
|
||||
"label.powered-by": "Betribe dur {name}",
|
||||
"label.previous": "Previous",
|
||||
"label.previous-period": "Previous period",
|
||||
"label.previous-year": "Previous year",
|
||||
"label.path": "Pfad",
|
||||
"label.paths": "Pfade",
|
||||
"label.powered-by": "Betriibe dur {name}",
|
||||
"label.previous": "Vorherig",
|
||||
"label.previous-period": "Vorherigi Periode",
|
||||
"label.previous-year": "Vorherigs Jahr",
|
||||
"label.profile": "Profil",
|
||||
"label.properties": "Properties",
|
||||
"label.property": "Property",
|
||||
"label.queries": "Abfrage",
|
||||
"label.query": "Query",
|
||||
"label.query": "Abfrag",
|
||||
"label.query-parameters": "Abfragparameter",
|
||||
"label.realtime": "Echtzit",
|
||||
"label.referrer": "Referrer",
|
||||
"label.referrers": "Referrer",
|
||||
"label.referrer": "Verwiiser",
|
||||
"label.referrers": "Verwiisendi",
|
||||
"label.refresh": "Aktualisiere",
|
||||
"label.regenerate": "Erneuere",
|
||||
"label.region": "Region",
|
||||
"label.regions": "Regionä",
|
||||
"label.remove": "Entferne",
|
||||
"label.remove-member": "Remove member",
|
||||
"label.reports": "Reports",
|
||||
"label.remove-member": "Mitglied entferne",
|
||||
"label.reports": "Brichte",
|
||||
"label.required": "Erforderlich",
|
||||
"label.reset": "Zruggsetze",
|
||||
"label.reset-website": "Statistik zruggsetze",
|
||||
"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.retention-description": "Mässed Sie d Verwiilduur vo Ihrere Website, indem Sie verfolged wie oft ihri Nutzer zruggkehred.",
|
||||
"label.revenue": "Umsatz",
|
||||
"label.revenue-description": "Lueged Sie sich Ihre Umsatz im Lauf vor Ziit a.",
|
||||
"label.revenue-property": "Umsatzeigenschafte",
|
||||
"label.role": "Rollä",
|
||||
"label.run-query": "Run query",
|
||||
"label.run-query": "Abfrag starte",
|
||||
"label.save": "Speichere",
|
||||
"label.screens": "Bildschirmuflösige",
|
||||
"label.search": "Search",
|
||||
"label.select": "Select",
|
||||
"label.select-date": "Select date",
|
||||
"label.select-role": "Select role",
|
||||
"label.search": "Sueche",
|
||||
"label.select": "Auswähle",
|
||||
"label.select-date": "Datä uuswähle",
|
||||
"label.select-role": "Rollä uuswähle",
|
||||
"label.select-website": "Websiite uuswähle",
|
||||
"label.session": "Session",
|
||||
"label.sessions": "Sessions",
|
||||
"label.session": "Sitzig",
|
||||
"label.sessions": "Sitzige",
|
||||
"label.settings": "Istellige",
|
||||
"label.share-url": "Freigab-URL",
|
||||
"label.single-day": "Ein Tag",
|
||||
"label.start-step": "Start Step",
|
||||
"label.steps": "Steps",
|
||||
"label.sum": "Sum",
|
||||
"label.start-step": "Startschritt",
|
||||
"label.steps": "Schritt",
|
||||
"label.sum": "Summe",
|
||||
"label.tablet": "Tablet",
|
||||
"label.team": "Team",
|
||||
"label.team-id": "Team ID",
|
||||
"label.team-manager": "Team manager",
|
||||
"label.team-manager": "Team Manager",
|
||||
"label.team-member": "Team Mitglied",
|
||||
"label.team-name": "Team name",
|
||||
"label.team-name": "Team Name",
|
||||
"label.team-owner": "Team Bsitzer",
|
||||
"label.team-view-only": "Team view only",
|
||||
"label.team-websites": "Team websites",
|
||||
"label.team-view-only": "Nur für Teammitglieder sichtbar",
|
||||
"label.team-websites": "Team Websiite",
|
||||
"label.teams": "Teams",
|
||||
"label.theme": "Thema",
|
||||
"label.this-month": "De Monet",
|
||||
"label.this-week": "Die Wuche",
|
||||
"label.this-year": "Das Jahr",
|
||||
"label.this-month": "Dä Monet",
|
||||
"label.this-week": "Diä Wuuche",
|
||||
"label.this-year": "Das Johr",
|
||||
"label.timezone": "Ziitzone",
|
||||
"label.title": "Titel",
|
||||
"label.today": "Hüt",
|
||||
"label.toggle-charts": "Schaubilder umschalte",
|
||||
"label.toggle-charts": "Charts umschalte",
|
||||
"label.total": "Total",
|
||||
"label.total-records": "Total records",
|
||||
"label.total-records": "Gsamti Datesätz",
|
||||
"label.tracking-code": "Tracking Code",
|
||||
"label.transactions": "Transactions",
|
||||
"label.transfer": "Transfer",
|
||||
"label.transfer-website": "Transfer website",
|
||||
"label.true": "True",
|
||||
"label.type": "Type",
|
||||
"label.unique": "Unique",
|
||||
"label.unique-visitors": "Eidütigi Bsuecher",
|
||||
"label.uniqueCustomers": "Unique Customers",
|
||||
"label.transactions": "Transaktione",
|
||||
"label.transfer": "Transferiere",
|
||||
"label.transfer-website": "Websiite transferiere",
|
||||
"label.true": "Wahr",
|
||||
"label.type": "Typ",
|
||||
"label.unique": "Einzigartigi",
|
||||
"label.unique-visitors": "Einzigartigi Bsuecher",
|
||||
"label.uniqueCustomers": "Einzigartigi Kunde",
|
||||
"label.unknown": "Unbekannt",
|
||||
"label.untitled": "Untitled",
|
||||
"label.untitled": "Unbennant",
|
||||
"label.update": "Update",
|
||||
"label.url": "URL",
|
||||
"label.urls": "URLs",
|
||||
"label.user": "Benutzer",
|
||||
"label.user-property": "User Property",
|
||||
"label.user-property": "Benutzereigeschafte",
|
||||
"label.username": "Benutzername",
|
||||
"label.users": "Benutzer",
|
||||
"label.utm": "UTM",
|
||||
"label.utm-description": "Track your campaigns through UTM parameters.",
|
||||
"label.value": "Value",
|
||||
"label.utm-description": "Tracked Sie Ihri Kampagnen mit UTM Parameters.",
|
||||
"label.value": "Wärt",
|
||||
"label.view": "Azeige",
|
||||
"label.view-details": "Details azeige",
|
||||
"label.view-only": "View only",
|
||||
"label.view-only": "Nume aluege",
|
||||
"label.views": "Ufrüef",
|
||||
"label.views-per-visit": "Views per visit",
|
||||
"label.views-per-visit": "Ufrüef pro Bsuech",
|
||||
"label.visit-duration": "Durchschn. Bsuechsziit",
|
||||
"label.visitors": "Bsuecher",
|
||||
"label.visits": "Visits",
|
||||
"label.visits": "Bsüech",
|
||||
"label.website": "Website",
|
||||
"label.website-id": "Websiite ID",
|
||||
"label.websites": "Websiite",
|
||||
"label.window": "Window",
|
||||
"label.window": "Fenster",
|
||||
"label.yesterday": "Gester",
|
||||
"message.action-confirmation": "Type {confirmation} in the box below to confirm.",
|
||||
"message.action-confirmation": "Typed Sie {confirmation} is Feld underhalb um z bestätige.",
|
||||
"message.active-users": "{x} {x, plural, one {aktive Bsuecher} other {aktivi Bsuecher}}",
|
||||
"message.collected-data": "Collected data",
|
||||
"message.collected-data": "Gsammleti Date",
|
||||
"message.confirm-delete": "Sind Sie sich sicher, {target} zlösche?",
|
||||
"message.confirm-leave": "Sind Sie sich sicher, {target} zverlah?",
|
||||
"message.confirm-remove": "Are you sure you want to remove {target}?",
|
||||
"message.confirm-reset": "Sind Sie sicher, dass Sie dStatistike vo {target} zruggsetze wend?",
|
||||
"message.delete-team-warning": "Deleting a team will also delete all team websites.",
|
||||
"message.delete-website-warning": "Alli dezueghörige Date werdet ebefalls glöscht.",
|
||||
"message.error": "Es isch en Fehler uftrete.",
|
||||
"message.confirm-remove": "Sind Sie sich sicher, dass Sie {target} wänd entferne?",
|
||||
"message.confirm-reset": "Sind Sie sicher, dass Sie d Statistike vo {target} zruggsetze wänd?",
|
||||
"message.delete-team-warning": "Es Team lösche dued ebefalls alli team Websiite lösche.",
|
||||
"message.delete-website-warning": "Alli dezueghörige Date werded ebefalls glöscht.",
|
||||
"message.error": "Es isch en Fehler ufträte.",
|
||||
"message.event-log": "{event} uf {url}",
|
||||
"message.go-to-settings": "Zu de Istellige",
|
||||
"message.incorrect-username-password": "Falschs Passwort oder Benutzername.",
|
||||
"message.incorrect-username-password": "Falsches Passwort oder Benutzername.",
|
||||
"message.invalid-domain": "Ungültigi Domain",
|
||||
"message.min-password-length": "Miminamli längi vo {n} Zeiche",
|
||||
"message.new-version-available": "A new version of Umami {version} is available!",
|
||||
"message.new-version-available": "Es isch en neue Version vo Umami {version} verfügbar!",
|
||||
"message.no-data-available": "Kei Date vorhande.",
|
||||
"message.no-event-data": "No event data is available.",
|
||||
"message.no-event-data": "Es sind kei Event Date verfügbar.",
|
||||
"message.no-match-password": "Passwörter stimmed ned überi",
|
||||
"message.no-results-found": "No results were found.",
|
||||
"message.no-results-found": "Kei Ergäbnis gfunde.",
|
||||
"message.no-team-websites": "Dem Team sind kei Websiite zuegordnet.",
|
||||
"message.no-teams": "Bisher sind no kei Teams erstellt worde.",
|
||||
"message.no-users": "Da gits kei Benutzer",
|
||||
"message.no-websites-configured": "Es isch kei Websiite vorhande.",
|
||||
"message.page-not-found": "Siite ned gfunde.",
|
||||
"message.reset-website": "To reset this website, type {confirmation} in the box below to confirm.",
|
||||
"message.reset-website": "Um die Websiite zruggzsetze, typed Sie {confirmation} is Feld unde dran.",
|
||||
"message.reset-website-warning": "Alli Date für die Websiite werdet glöscht, nur de Tracking Code blibt bestah.",
|
||||
"message.saved": "Erfolgrich gspeichert.",
|
||||
"message.share-url": "Ihri Websiitestatistik isch under de folgende URL öffentlich zuegänglich:",
|
||||
"message.team-already-member": "Sie sind bereits es Mitglied vo dem Team.",
|
||||
"message.team-already-member": "Sie sind bereits es Mitglied vo däm Team.",
|
||||
"message.team-not-found": "Team nöd gfunde.",
|
||||
"message.team-websites-info": "Websiite chönd vo jedem im Team agluegt werde",
|
||||
"message.team-websites-info": "Websiite chöi vo jedem im Team agluegt werde",
|
||||
"message.tracking-code": "Tracking Code",
|
||||
"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": "Benutzer glöscht.",
|
||||
"message.viewed-page": "Viewed page",
|
||||
"message.visitor-log": "Bsuecher us {country} benutzt {browser} uf {os} {device}",
|
||||
"message.visitors-dropped-off": "Visitors dropped off"
|
||||
}
|
||||
"message.transfer-team-website-to-user": "Websiite uf zu Ihrem Account transferiere?",
|
||||
"message.transfer-user-website-to-team": "Wähled Sie s Team zum däm Websiite transferiert werde söll.",
|
||||
"message.transfer-website": "Übertraged Sie d Websiite Eigetümerrecht uf Ihre Account oder uf es anders Team",
|
||||
"message.triggered-event": "Usglösts Ereigniss",
|
||||
"message.user-deleted": "Bnutzer glöscht.",
|
||||
"message.viewed-page": "Siite agluegt",
|
||||
"message.visitor-log": "Bsuecher us {country} nutzt {browser} uf {os} {device}",
|
||||
"message.visitors-dropped-off": "Bsuercher verlore"
|
||||
}
|
@ -67,8 +67,8 @@
|
||||
"label.enable-share-url": "Freigabe-URL aktivieren",
|
||||
"label.end-step": "Schlussschritt",
|
||||
"label.entry": "Eingangs-URL",
|
||||
"label.event": "Ereigniss",
|
||||
"label.event-data": "Ereignissdaten",
|
||||
"label.event": "Ereignis",
|
||||
"label.event-data": "Ereignisdaten",
|
||||
"label.events": "Ereignisse",
|
||||
"label.exit": "Ausgangs-URL",
|
||||
"label.false": "Falsch",
|
||||
@ -271,7 +271,7 @@
|
||||
"message.transfer-team-website-to-user": "Diese Website zu Ihrem Account transferieren?",
|
||||
"message.transfer-user-website-to-team": "Wählen Sie ein Team aus, zu dem die Website transferiert werden soll.",
|
||||
"message.transfer-website": "Übertragen Sie die Eigentümerrechte zu Ihrem Account oder einem anderen Team.",
|
||||
"message.triggered-event": "Ausgelöstes Ereigniss",
|
||||
"message.triggered-event": "Ereignis ausgelöst",
|
||||
"message.user-deleted": "Benutzer gelöscht.",
|
||||
"message.viewed-page": "Seite besucht",
|
||||
"message.visitor-log": "Besucher aus {country} benutzt {browser} auf {os} {device}",
|
||||
|
@ -66,7 +66,7 @@
|
||||
"label.edit-member": "Modifier le membre",
|
||||
"label.enable-share-url": "Activer l'URL de partage",
|
||||
"label.end-step": "End Step",
|
||||
"label.entry": "Entry URL",
|
||||
"label.entry": "URL d'entrée",
|
||||
"label.event": "Évènement",
|
||||
"label.event-data": "Données d'évènements",
|
||||
"label.events": "Évènements",
|
||||
@ -78,12 +78,12 @@
|
||||
"label.filter-combined": "Combiné",
|
||||
"label.filter-raw": "Brut",
|
||||
"label.filters": "Filtres",
|
||||
"label.first-seen": "First seen",
|
||||
"label.first-seen": "Vu pour la première fois",
|
||||
"label.funnel": "Entonnoir",
|
||||
"label.funnel-description": "Suivi des conversions et des taux d'abandons.",
|
||||
"label.goal": "Goal",
|
||||
"label.goals": "Goals",
|
||||
"label.goals-description": "Track your goals for pageviews and events.",
|
||||
"label.goals-description": "Suivez vos objectifs en matière de pages vues et d'événements.",
|
||||
"label.greater-than": "Supérieur à",
|
||||
"label.greater-than-equals": "Supérieur ou égal à",
|
||||
"label.host": "Host",
|
||||
@ -97,7 +97,7 @@
|
||||
"label.join": "Rejoindre",
|
||||
"label.join-team": "Rejoindre une équipe",
|
||||
"label.journey": "Journey",
|
||||
"label.journey-description": "Understand how users navigate through your website.",
|
||||
"label.journey-description": "Comprendre comment les utilisateurs naviguent sur votre site web.",
|
||||
"label.language": "Langue",
|
||||
"label.languages": "Langues",
|
||||
"label.laptop": "Portable",
|
||||
@ -137,12 +137,12 @@
|
||||
"label.path": "Path",
|
||||
"label.paths": "Paths",
|
||||
"label.powered-by": "Propulsé par {name}",
|
||||
"label.previous": "Previous",
|
||||
"label.previous-period": "Previous period",
|
||||
"label.previous-year": "Previous year",
|
||||
"label.previous": "Précédent",
|
||||
"label.previous-period": "Période précédente",
|
||||
"label.previous-year": "Année précédente",
|
||||
"label.profile": "Profil",
|
||||
"label.properties": "Properties",
|
||||
"label.property": "Property",
|
||||
"label.properties": "Propriétés",
|
||||
"label.property": "Propriété",
|
||||
"label.queries": "Requêtes",
|
||||
"label.query": "Requête",
|
||||
"label.query-parameters": "Paramètres de requête",
|
||||
@ -162,14 +162,14 @@
|
||||
"label.retention": "Rétention",
|
||||
"label.retention-description": "Mesure de l'attractivité du site en visualisant les taux de visiteurs qui reviennent.",
|
||||
"label.revenue": "Revenue",
|
||||
"label.revenue-description": "Look into your revenue across time.",
|
||||
"label.revenue-property": "Revenue Property",
|
||||
"label.revenue-description": "Examinez vos revenus au fil du temps.",
|
||||
"label.revenue-property": "Propriétés des revenues",
|
||||
"label.role": "Rôle",
|
||||
"label.run-query": "Éxécuter la requête",
|
||||
"label.save": "Enregistrer",
|
||||
"label.screens": "Résolutions d'écran",
|
||||
"label.search": "Rechercher",
|
||||
"label.select": "Select",
|
||||
"label.select": "Selectionner",
|
||||
"label.select-date": "Choisir une période",
|
||||
"label.select-role": "Choisir un rôle",
|
||||
"label.select-website": "Choisir un site",
|
||||
@ -178,17 +178,17 @@
|
||||
"label.settings": "Paramètres",
|
||||
"label.share-url": "URL de partage",
|
||||
"label.single-day": "Journée",
|
||||
"label.start-step": "Start Step",
|
||||
"label.start-step": "Etape de démarrage",
|
||||
"label.steps": "Étapes",
|
||||
"label.sum": "Somme",
|
||||
"label.tablet": "Tablette",
|
||||
"label.team": "Équipe",
|
||||
"label.team-id": "ID d'équipe",
|
||||
"label.team-manager": "Team manager",
|
||||
"label.team-manager": "Manager de l'équipe",
|
||||
"label.team-member": "Membre de l'équipe",
|
||||
"label.team-name": "Nom de l'équipe",
|
||||
"label.team-owner": "Propriétaire de l'équipe",
|
||||
"label.team-view-only": "Team view only",
|
||||
"label.team-view-only": "Vue d'équipe uniquement",
|
||||
"label.team-websites": "Sites d'équipes",
|
||||
"label.teams": "Équipes",
|
||||
"label.theme": "Thème",
|
||||
@ -209,14 +209,14 @@
|
||||
"label.type": "Type",
|
||||
"label.unique": "Unique",
|
||||
"label.unique-visitors": "Visiteurs uniques",
|
||||
"label.uniqueCustomers": "Unique Customers",
|
||||
"label.uniqueCustomers": "Clients uniques",
|
||||
"label.unknown": "Inconnu",
|
||||
"label.untitled": "Sans titre",
|
||||
"label.update": "Modifier",
|
||||
"label.url": "URL",
|
||||
"label.urls": "URLs",
|
||||
"label.user": "Utilisateur",
|
||||
"label.user-property": "User Property",
|
||||
"label.user-property": "Propriétés d'utilisateurs",
|
||||
"label.username": "Nom d'utilisateur",
|
||||
"label.users": "Utilisateurs",
|
||||
"label.utm": "UTM",
|
||||
|
@ -160,7 +160,7 @@
|
||||
"label.reset": "초기화",
|
||||
"label.reset-website": "웹사이트 초기화",
|
||||
"label.retention": "리텐션",
|
||||
"label.retention-description": "사용자가 얼마나 자주 돌아오는지를 추적하여 웹사이트의 리텐션을 측정하십시오.",
|
||||
"label.retention-description": "사용자가 얼마나 자주 돌아오는지를 추적하여 웹사이트의 리텐션을 측정하세요.",
|
||||
"label.revenue": "수익",
|
||||
"label.revenue-description": "시간대별 수익을 살펴보세요.",
|
||||
"label.revenue-property": "수익 속성",
|
||||
@ -220,14 +220,14 @@
|
||||
"label.username": "사용자 이름",
|
||||
"label.users": "사용자",
|
||||
"label.utm": "UTM",
|
||||
"label.utm-description": "UTM 매개변수를 통해 캠페인을 추적합니다.",
|
||||
"label.utm-description": "UTM 매개변수를 통해 캠페인을 추적하세요.",
|
||||
"label.value": "값",
|
||||
"label.view": "보기",
|
||||
"label.view-details": "자세히 보기",
|
||||
"label.view-only": "보기 전용",
|
||||
"label.views": "조회",
|
||||
"label.views-per-visit": "방문당 조회",
|
||||
"label.visit-duration": "평균 방문 시간",
|
||||
"label.visit-duration": "방문 시간",
|
||||
"label.visitors": "방문자",
|
||||
"label.visits": "방문",
|
||||
"label.website": "웹사이트",
|
||||
@ -244,7 +244,7 @@
|
||||
"message.confirm-reset": "{target}을(를) 초기화하시겠습니까?",
|
||||
"message.delete-team-warning": "팀을 삭제하면 팀에 등록된 모든 웹사이트도 삭제됩니다.",
|
||||
"message.delete-website-warning": "관련된 모든 데이터가 삭제됩니다.",
|
||||
"message.error": "오류가 발생했습니다.",
|
||||
"message.error": "문제가 발생했습니다.",
|
||||
"message.event-log": "{event} - {url}",
|
||||
"message.go-to-settings": "설정으로 이동",
|
||||
"message.incorrect-username-password": "사용자 이름 또는 비밀번호를 잘못 입력했습니다.",
|
||||
|
@ -5,8 +5,8 @@
|
||||
"label.add": "Adaugă",
|
||||
"label.add-description": "Adaugă descriere",
|
||||
"label.add-member": "Adaugă membru",
|
||||
"label.add-step": "Add step",
|
||||
"label.add-website": "Adăugare site web",
|
||||
"label.add-step": "Adaugă pas",
|
||||
"label.add-website": "Adaugă site web",
|
||||
"label.admin": "Administrator",
|
||||
"label.after": "După",
|
||||
"label.all": "Toate",
|
||||
@ -24,12 +24,12 @@
|
||||
"label.cities": "Orașe",
|
||||
"label.city": "Oraș",
|
||||
"label.clear-all": "Șterge tot",
|
||||
"label.compare": "Compare",
|
||||
"label.compare": "Compară",
|
||||
"label.confirm": "Confirm",
|
||||
"label.confirm-password": "Confirmare parolă",
|
||||
"label.contains": "Conține",
|
||||
"label.continue": "Continuă",
|
||||
"label.count": "Count",
|
||||
"label.count": "Număr",
|
||||
"label.countries": "Țări",
|
||||
"label.country": "Țară",
|
||||
"label.create": "Crează",
|
||||
@ -37,21 +37,21 @@
|
||||
"label.create-team": "Crează echipă",
|
||||
"label.create-user": "Crează utilizator",
|
||||
"label.created": "Creat",
|
||||
"label.created-by": "Created By",
|
||||
"label.current": "Current",
|
||||
"label.created-by": "Creat de",
|
||||
"label.current": "Curent",
|
||||
"label.current-password": "Parola curentă",
|
||||
"label.custom-range": "Interval personalizat",
|
||||
"label.dashboard": "Tablou de bord",
|
||||
"label.data": "Date",
|
||||
"label.date": "Data",
|
||||
"label.date-range": "Interval de date",
|
||||
"label.date": "Dată",
|
||||
"label.date-range": "Interval",
|
||||
"label.day": "Zi",
|
||||
"label.default-date-range": "Interval de date implicit",
|
||||
"label.default-date-range": "Interval implicit",
|
||||
"label.delete": "Șterge",
|
||||
"label.delete-report": "Șterge raport",
|
||||
"label.delete-team": "Șterge echipă",
|
||||
"label.delete-user": "Șterge utilizator",
|
||||
"label.delete-website": "Ștergere site web",
|
||||
"label.delete-website": "Șterge site web",
|
||||
"label.description": "Descriere",
|
||||
"label.desktop": "Desktop",
|
||||
"label.details": "Detalii",
|
||||
@ -65,12 +65,12 @@
|
||||
"label.edit-dashboard": "Editare tablou de bord",
|
||||
"label.edit-member": "Editare membru",
|
||||
"label.enable-share-url": "Activare adresă URL de distribuire",
|
||||
"label.end-step": "End Step",
|
||||
"label.entry": "Entry URL",
|
||||
"label.end-step": "Pas final",
|
||||
"label.entry": "URL de intrare",
|
||||
"label.event": "Eveniment",
|
||||
"label.event-data": "Date despre eveniment",
|
||||
"label.events": "Evenimente",
|
||||
"label.exit": "Exit URL",
|
||||
"label.exit": "URL de ieșire",
|
||||
"label.false": "Fals",
|
||||
"label.field": "Câmp",
|
||||
"label.fields": "Câmpuri",
|
||||
@ -78,12 +78,12 @@
|
||||
"label.filter-combined": "Combinat",
|
||||
"label.filter-raw": "Brut",
|
||||
"label.filters": "Filtre",
|
||||
"label.first-seen": "First seen",
|
||||
"label.first-seen": "Văzut pentru prima dată",
|
||||
"label.funnel": "Parcursul utilizatorului",
|
||||
"label.funnel-description": "Înțelege rata de conversie și rata de abandon a utilizatorilor.",
|
||||
"label.goal": "Goal",
|
||||
"label.goals": "Goals",
|
||||
"label.goals-description": "Track your goals for pageviews and events.",
|
||||
"label.goal": "Obiectiv",
|
||||
"label.goals": "Obiective",
|
||||
"label.goals-description": "Urmărește obiectivele de vizualizări și evenimente.",
|
||||
"label.greater-than": "Mai mare decât",
|
||||
"label.greater-than-equals": "Mai mare sau egal cu",
|
||||
"label.host": "Host",
|
||||
@ -96,15 +96,15 @@
|
||||
"label.is-set": "Este setat",
|
||||
"label.join": "Alătură-te",
|
||||
"label.join-team": "Alătură-te echipei",
|
||||
"label.journey": "Journey",
|
||||
"label.journey-description": "Understand how users navigate through your website.",
|
||||
"label.journey": "Traseu",
|
||||
"label.journey-description": "Înțelege cum navighează vizitatorii prin website.",
|
||||
"label.language": "Limbă",
|
||||
"label.languages": "Limbi",
|
||||
"label.laptop": "Laptop",
|
||||
"label.last-days": "Ultimele {x} zile",
|
||||
"label.last-hours": "Ultimele {x} ore",
|
||||
"label.last-months": "Last {x} months",
|
||||
"label.last-seen": "Last seen",
|
||||
"label.last-months": "Ultimele {x} luni",
|
||||
"label.last-seen": "Văzut ultima dată",
|
||||
"label.leave": "Părăsește",
|
||||
"label.leave-team": "Părăsește echipa",
|
||||
"label.less-than": "Mai puțin decât",
|
||||
@ -134,15 +134,15 @@
|
||||
"label.pageTitle": "Titlul paginii",
|
||||
"label.pages": "Pagini",
|
||||
"label.password": "Parolă",
|
||||
"label.path": "Path",
|
||||
"label.paths": "Paths",
|
||||
"label.path": "Rută",
|
||||
"label.paths": "Rute",
|
||||
"label.powered-by": "Cu sprijinul {name}",
|
||||
"label.previous": "Previous",
|
||||
"label.previous-period": "Previous period",
|
||||
"label.previous-year": "Previous year",
|
||||
"label.previous": "Anterior",
|
||||
"label.previous-period": "Perioda anterioară",
|
||||
"label.previous-year": "Anul anterior",
|
||||
"label.profile": "Profil",
|
||||
"label.properties": "Properties",
|
||||
"label.property": "Property",
|
||||
"label.properties": "Proprietăți",
|
||||
"label.property": "Proprietate",
|
||||
"label.queries": "Interogări",
|
||||
"label.query": "Interogare",
|
||||
"label.query-parameters": "Parametri de interogare",
|
||||
@ -161,8 +161,8 @@
|
||||
"label.reset-website": "Resetează statisticile pentru site",
|
||||
"label.retention": "Retenție",
|
||||
"label.retention-description": "Măsoară atractivitatea site-ului tău prin urmărirea frecvenței cu care utilizatorii se întorc.",
|
||||
"label.revenue": "Revenue",
|
||||
"label.revenue-description": "Look into your revenue across time.",
|
||||
"label.revenue": "Venit",
|
||||
"label.revenue-description": "Urmărește venitul în timp.",
|
||||
"label.revenue-property": "Revenue Property",
|
||||
"label.role": "Rol",
|
||||
"label.run-query": "Execută interogarea",
|
||||
@ -173,18 +173,18 @@
|
||||
"label.select-date": "Selectează data",
|
||||
"label.select-role": "Selectează rolul",
|
||||
"label.select-website": "Selectează website",
|
||||
"label.session": "Session",
|
||||
"label.session": "Sesiune",
|
||||
"label.sessions": "Sesiuni",
|
||||
"label.settings": "Setări",
|
||||
"label.share-url": "Partajare URL",
|
||||
"label.single-day": "O singură zi",
|
||||
"label.start-step": "Start Step",
|
||||
"label.steps": "Steps",
|
||||
"label.start-step": "Pas de început",
|
||||
"label.steps": "Pași",
|
||||
"label.sum": "Sumă",
|
||||
"label.tablet": "Tabletă",
|
||||
"label.team": "Echipă",
|
||||
"label.team-id": "ID Echipa",
|
||||
"label.team-manager": "Team manager",
|
||||
"label.team-id": "ID Echipă",
|
||||
"label.team-manager": "Manager echipă",
|
||||
"label.team-member": "Membru echipă",
|
||||
"label.team-name": "Nume echipă",
|
||||
"label.team-owner": "Titular echipă",
|
||||
@ -202,34 +202,34 @@
|
||||
"label.total": "Total",
|
||||
"label.total-records": "Total înregistrări",
|
||||
"label.tracking-code": "Cod de urmărire",
|
||||
"label.transactions": "Transactions",
|
||||
"label.transactions": "Tranzacții",
|
||||
"label.transfer": "Transfer",
|
||||
"label.transfer-website": "Transfer website",
|
||||
"label.true": "Adevărat",
|
||||
"label.type": "Tip",
|
||||
"label.unique": "Unici",
|
||||
"label.unique-visitors": "Vizitatori unici",
|
||||
"label.uniqueCustomers": "Unique Customers",
|
||||
"label.uniqueCustomers": "Clienți unici",
|
||||
"label.unknown": "Necunoscut",
|
||||
"label.untitled": "Fără titlu",
|
||||
"label.update": "Update",
|
||||
"label.url": "URL",
|
||||
"label.urls": "URLs",
|
||||
"label.user": "Utilizator",
|
||||
"label.user-property": "User Property",
|
||||
"label.user-property": "Proprietatea utilizatorului",
|
||||
"label.username": "Nume utilizator",
|
||||
"label.users": "Utilizatori",
|
||||
"label.utm": "UTM",
|
||||
"label.utm-description": "Track your campaigns through UTM parameters.",
|
||||
"label.utm-description": "Urmărește campaniile tale cu parametri UTM.",
|
||||
"label.value": "Valoare",
|
||||
"label.view": "Vizualizare",
|
||||
"label.view-details": "Vizualizare detalii",
|
||||
"label.view-only": "Doar vizualizare",
|
||||
"label.views": "Vizualizări",
|
||||
"label.views-per-visit": "Views per visit",
|
||||
"label.views-per-visit": "Vizualizări per vizită",
|
||||
"label.visit-duration": "Timp mediu de vizitare",
|
||||
"label.visitors": "Vizitatori",
|
||||
"label.visits": "Visits",
|
||||
"label.visits": "Vizite",
|
||||
"label.website": "Website",
|
||||
"label.website-id": "ID Website",
|
||||
"label.websites": "Site-uri web",
|
||||
@ -237,7 +237,7 @@
|
||||
"label.yesterday": "Ieri",
|
||||
"message.action-confirmation": "Scrie {confirmation} în câmpul de mai jos pentru a confirma.",
|
||||
"message.active-users": "{x} {x, plural, one {vizitator activ} other {vizitatori activi}}",
|
||||
"message.collected-data": "Collected data",
|
||||
"message.collected-data": "Date colectate",
|
||||
"message.confirm-delete": "Ești sigur că vrei să ștergi {target}?",
|
||||
"message.confirm-leave": "Ești sigur că vrei să părăsești {target}?",
|
||||
"message.confirm-remove": "Ești sigur că vrei să ștergi {target}?",
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user