diff --git a/.github/ISSUE_TEMPLATE/1.bug_report.yml b/.github/ISSUE_TEMPLATE/1.bug_report.yml index 2404918b8..ff7a181e3 100644 --- a/.github/ISSUE_TEMPLATE/1.bug_report.yml +++ b/.github/ISSUE_TEMPLATE/1.bug_report.yml @@ -1,5 +1,5 @@ -name: '🐛 Bug Report' -description: Create a bug report for Umami. +name: "🐛 Bug Report" +description: Create a bug report for Syncfuse. body: - type: textarea attributes: @@ -14,7 +14,7 @@ body: options: - PostgreSQL - MySQL - - Umami Cloud + - Syncfuse Cloud validations: required: true - type: textarea @@ -24,13 +24,13 @@ body: render: shell - type: input attributes: - label: Which Umami version are you using? (if relevant) - description: 'For example: 2.18.0, 2.15.1, 1.39.0, etc' + label: Which Syncfuse version are you using? (if relevant) + description: "For example: 2.18.0, 2.15.1, 1.39.0, etc" - type: input attributes: label: Which browser are you using? (if relevant) - description: 'For example: Chrome, Edge, Firefox, etc' + description: "For example: Chrome, Edge, Firefox, etc" - type: input attributes: label: How are you deploying your application? (if relevant) - description: 'For example: Vercel, Railway, Docker, etc' + description: "For example: Vercel, Railway, Docker, etc" diff --git a/.github/ISSUE_TEMPLATE/2.feature_request.yml b/.github/ISSUE_TEMPLATE/2.feature_request.yml index 529a6c732..f7537c6e7 100644 --- a/.github/ISSUE_TEMPLATE/2.feature_request.yml +++ b/.github/ISSUE_TEMPLATE/2.feature_request.yml @@ -1,5 +1,5 @@ -name: '✨ Feature Request' -description: Create a feature or enhancement request for Umami. +name: "✨ Feature Request" +description: Create a feature or enhancement request for Syncfuse. body: - type: textarea attributes: diff --git a/LICENSE b/LICENSE index eff413693..e01199f36 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Umami Software, Inc. +Copyright (c) 2022 Syncfuse Analytics Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file +THE SOFTWARE. diff --git a/README.md b/README.md index cd365a68d..7d07334a5 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Umami Logo

-

Umami

+

Syncfuse a

- Umami is a simple, fast, privacy-focused alternative to Google Analytics. + Syncfuse is a simple, fast, privacy-focused alternative to Google Analytics.

@@ -38,7 +38,7 @@ cd umami pnpm install ``` -### Configure Umami +### Configure Syncfuse Create an `.env` file with the following: @@ -58,7 +58,7 @@ postgresql://username:mypassword@localhost:5432/mydb pnpm run build ``` -The build step will create tables in your database if you are installing for the first time. It will also create a login user with username **admin** and password **umami**. +The build step will create tables in your database if you are installing for the first time. It will also create a login user with username **admin** and password **syncfuse**. ### Start the Application @@ -72,7 +72,7 @@ By default, this will launch the application on `http://localhost:3000`. You wil ## 🐳 Installing with Docker -Umami provides Docker images as well as a Docker compose file for easy deployment. +Syncfuse provides Docker images as well as a Docker compose file for easy deployment. Docker image: @@ -80,7 +80,7 @@ Docker image: docker pull docker.umami.is/umami-software/umami:latest ``` -Docker compose (Runs Umami with a PostgreSQL database): +Docker compose (Runs Syncfuse with a PostgreSQL database): ```bash docker compose up -d diff --git a/app.json b/app.json index cec5fda10..c5a67ad83 100644 --- a/app.json +++ b/app.json @@ -1,6 +1,6 @@ { - "name": "Umami", - "description": "Umami is a simple, fast, website analytics alternative to Google Analytics.", + "name": "Syncfuse", + "description": "Syncfuse is a simple, fast, website analytics alternative to Google Analytics.", "keywords": ["analytics", "charts", "statistics", "web-analytics"], "website": "https://umami.is", "repository": "https://github.com/umami-software/umami", diff --git a/cypress.config.ts b/cypress.config.ts index c1100467d..2e039da61 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -1,13 +1,13 @@ -import { defineConfig } from 'cypress'; +import { defineConfig } from "cypress"; export default defineConfig({ e2e: { - baseUrl: 'http://localhost:3000', + baseUrl: "http://localhost:3000", }, // default username / password on init env: { - umami_user: 'admin', - umami_password: 'umami', - umami_user_id: '41e2b680-648e-4b09-bcd7-3e2b10c06264', + syncfuse_user: "admin", + syncfuse_password: "syncfuse", + syncfuse_user_id: "41e2b680-648e-4b09-bcd7-3e2b10c06264", }, }); diff --git a/cypress/docker-compose.yml b/cypress/docker-compose.yml index 01a47bd8c..eba14a5aa 100644 --- a/cypress/docker-compose.yml +++ b/cypress/docker-compose.yml @@ -1,13 +1,13 @@ --- -version: '3' +version: "3" services: - umami: + syncfuse: build: ../ #image: ghcr.io/umami-software/umami:postgresql-latest ports: - - '3000:3000' + - "3000:3000" environment: - DATABASE_URL: postgresql://umami:umami@db:5432/umami + DATABASE_URL: postgresql://syncfuse:syncfuse@db:5432/syncfuse DATABASE_TYPE: postgresql APP_SECRET: replace-me-with-a-random-string depends_on: @@ -15,33 +15,33 @@ services: condition: service_healthy restart: always healthcheck: - test: ['CMD-SHELL', 'curl http://localhost:3000/api/heartbeat'] + test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"] interval: 5s timeout: 5s retries: 5 db: image: postgres:15-alpine environment: - POSTGRES_DB: umami - POSTGRES_USER: umami - POSTGRES_PASSWORD: umami + POSTGRES_DB: syncfuse + POSTGRES_USER: syncfuse + POSTGRES_PASSWORD: syncfuse volumes: - - umami-db-data:/var/lib/postgresql/data + - syncfuse-db-data:/var/lib/postgresql/data restart: always healthcheck: - test: ['CMD-SHELL', 'pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}'] + test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 5s timeout: 5s retries: 5 cypress: - image: 'cypress/included:13.6.0' + image: "cypress/included:13.6.0" depends_on: - - umami + - syncfuse - db environment: - - CYPRESS_baseUrl=http://umami:3000 - - CYPRESS_umami_user=admin - - CYPRESS_umami_password=umami + - CYPRESS_baseUrl=http://syncfuse:3000 + - CYPRESS_syncfuse_user=admin + - CYPRESS_syncfuse_password=syncfuse volumes: - ./tsconfig.json:/tsconfig.json - ../cypress.config.ts:/cypress.config.ts @@ -49,4 +49,4 @@ services: - ../node_modules/:/node_modules - ../src/lib/crypto.ts:/src/lib/crypto.ts volumes: - umami-db-data: + syncfuse-db-data: diff --git a/cypress/e2e/api-team.cy.ts b/cypress/e2e/api-team.cy.ts index 22811130f..ca0b1948a 100644 --- a/cypress/e2e/api-team.cy.ts +++ b/cypress/e2e/api-team.cy.ts @@ -1,191 +1,191 @@ -describe('Team API tests', () => { +describe("Team API tests", () => { Cypress.session.clearAllSavedSessions(); let teamId; let userId; before(() => { - cy.login(Cypress.env('umami_user'), Cypress.env('umami_password')); - cy.fixture('users').then(data => { + cy.login(Cypress.env("syncfuse_user"), Cypress.env("syncfuse_password")); + cy.fixture("users").then((data) => { const userCreate = data.userCreate; cy.request({ - method: 'POST', - url: '/api/users', + method: "POST", + url: "/api/users", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: userCreate, - }).then(response => { + }).then((response) => { userId = response.body.id; expect(response.status).to.eq(200); - expect(response.body).to.have.property('username', 'cypress1'); - expect(response.body).to.have.property('role', 'user'); + expect(response.body).to.have.property("username", "cypress1"); + expect(response.body).to.have.property("role", "user"); }); }); }); - it('Creates a team.', () => { - cy.fixture('teams').then(data => { + it("Creates a team.", () => { + cy.fixture("teams").then((data) => { const teamCreate = data.teamCreate; cy.request({ - method: 'POST', - url: '/api/teams', + method: "POST", + url: "/api/teams", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: teamCreate, - }).then(response => { + }).then((response) => { teamId = response.body[0].id; expect(response.status).to.eq(200); - expect(response.body[0]).to.have.property('name', 'cypress'); - expect(response.body[1]).to.have.property('role', 'team-owner'); + expect(response.body[0]).to.have.property("name", "cypress"); + expect(response.body[1]).to.have.property("role", "team-owner"); }); }); }); - it('Gets a teams by ID.', () => { + it("Gets a teams by ID.", () => { cy.request({ - method: 'GET', + method: "GET", url: `/api/teams/${teamId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('id', teamId); + expect(response.body).to.have.property("id", teamId); }); }); - it('Updates a team.', () => { - cy.fixture('teams').then(data => { + it("Updates a team.", () => { + cy.fixture("teams").then((data) => { const teamUpdate = data.teamUpdate; cy.request({ - method: 'POST', + method: "POST", url: `/api/teams/${teamId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: teamUpdate, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('id', teamId); - expect(response.body).to.have.property('name', 'cypressUpdate'); + expect(response.body).to.have.property("id", teamId); + expect(response.body).to.have.property("name", "cypressUpdate"); }); }); }); - it('Get all users that belong to a team.', () => { + it("Get all users that belong to a team.", () => { cy.request({ - method: 'GET', + method: "GET", url: `/api/teams/${teamId}/users`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body.data[0]).to.have.property('id'); - expect(response.body.data[0]).to.have.property('teamId'); - expect(response.body.data[0]).to.have.property('userId'); - expect(response.body.data[0]).to.have.property('user'); + expect(response.body.data[0]).to.have.property("id"); + expect(response.body.data[0]).to.have.property("teamId"); + expect(response.body.data[0]).to.have.property("userId"); + expect(response.body.data[0]).to.have.property("user"); }); }); - it('Get a user belonging to a team.', () => { + it("Get a user belonging to a team.", () => { cy.request({ - method: 'GET', - url: `/api/teams/${teamId}/users/${Cypress.env('umami_user_id')}`, + method: "GET", + url: `/api/teams/${teamId}/users/${Cypress.env("syncfuse_user_id")}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('teamId'); - expect(response.body).to.have.property('userId'); - expect(response.body).to.have.property('role'); + expect(response.body).to.have.property("teamId"); + expect(response.body).to.have.property("userId"); + expect(response.body).to.have.property("role"); }); }); - it('Get all websites belonging to a team.', () => { + it("Get all websites belonging to a team.", () => { cy.request({ - method: 'GET', + method: "GET", url: `/api/teams/${teamId}/websites`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('data'); + expect(response.body).to.have.property("data"); }); }); - it('Add a user to a team.', () => { + it("Add a user to a team.", () => { cy.request({ - method: 'POST', + method: "POST", url: `/api/teams/${teamId}/users`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: { userId, - role: 'team-member', + role: "team-member", }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('userId', userId); - expect(response.body).to.have.property('role', 'team-member'); + expect(response.body).to.have.property("userId", userId); + expect(response.body).to.have.property("role", "team-member"); }); }); it(`Update a user's role on a team.`, () => { cy.request({ - method: 'POST', + method: "POST", url: `/api/teams/${teamId}/users/${userId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: { - role: 'team-view-only', + role: "team-view-only", }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('userId', userId); - expect(response.body).to.have.property('role', 'team-view-only'); + expect(response.body).to.have.property("userId", userId); + expect(response.body).to.have.property("role", "team-view-only"); }); }); it(`Remove a user from a team.`, () => { cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/teams/${teamId}/users/${userId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); }); }); - it('Deletes a team.', () => { + it("Deletes a team.", () => { cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/teams/${teamId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('ok', true); + expect(response.body).to.have.property("ok", true); }); }); diff --git a/cypress/e2e/api-user.cy.ts b/cypress/e2e/api-user.cy.ts index 696cd21e4..3c757cc4d 100644 --- a/cypress/e2e/api-user.cy.ts +++ b/cypress/e2e/api-user.cy.ts @@ -1,125 +1,125 @@ -describe('User API tests', () => { +describe("User API tests", () => { Cypress.session.clearAllSavedSessions(); before(() => { - cy.login(Cypress.env('umami_user'), Cypress.env('umami_password')); + cy.login(Cypress.env("syncfuse_user"), Cypress.env("syncfuse_password")); }); let userId; - it('Creates a user.', () => { - cy.fixture('users').then(data => { + it("Creates a user.", () => { + cy.fixture("users").then((data) => { const userCreate = data.userCreate; cy.request({ - method: 'POST', - url: '/api/users', + method: "POST", + url: "/api/users", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: userCreate, - }).then(response => { + }).then((response) => { userId = response.body.id; expect(response.status).to.eq(200); - expect(response.body).to.have.property('username', 'cypress1'); - expect(response.body).to.have.property('role', 'user'); + expect(response.body).to.have.property("username", "cypress1"); + expect(response.body).to.have.property("role", "user"); }); }); }); - it('Returns all users. Admin access is required.', () => { + it("Returns all users. Admin access is required.", () => { cy.request({ - method: 'GET', - url: '/api/admin/users', + method: "GET", + url: "/api/admin/users", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body.data[0]).to.have.property('id'); - expect(response.body.data[0]).to.have.property('username'); - expect(response.body.data[0]).to.have.property('password'); - expect(response.body.data[0]).to.have.property('role'); + expect(response.body.data[0]).to.have.property("id"); + expect(response.body.data[0]).to.have.property("username"); + expect(response.body.data[0]).to.have.property("password"); + expect(response.body.data[0]).to.have.property("role"); }); }); - it('Updates a user.', () => { - cy.fixture('users').then(data => { + it("Updates a user.", () => { + cy.fixture("users").then((data) => { const userUpdate = data.userUpdate; cy.request({ - method: 'POST', + method: "POST", url: `/api/users/${userId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: userUpdate, - }).then(response => { + }).then((response) => { userId = response.body.id; expect(response.status).to.eq(200); - expect(response.body).to.have.property('id', userId); - expect(response.body).to.have.property('username', 'cypress1'); - expect(response.body).to.have.property('role', 'view-only'); + expect(response.body).to.have.property("id", userId); + expect(response.body).to.have.property("username", "cypress1"); + expect(response.body).to.have.property("role", "view-only"); }); }); }); - it('Gets a user by ID.', () => { + it("Gets a user by ID.", () => { cy.request({ - method: 'GET', + method: "GET", url: `/api/users/${userId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('id', userId); - expect(response.body).to.have.property('username', 'cypress1'); - expect(response.body).to.have.property('role', 'view-only'); + expect(response.body).to.have.property("id", userId); + expect(response.body).to.have.property("username", "cypress1"); + expect(response.body).to.have.property("role", "view-only"); }); }); - it('Deletes a user.', () => { + it("Deletes a user.", () => { cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/users/${userId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('ok', true); + expect(response.body).to.have.property("ok", true); }); }); - it('Gets all websites that belong to a user.', () => { + it("Gets all websites that belong to a user.", () => { cy.request({ - method: 'GET', + method: "GET", url: `/api/users/${userId}/websites`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('data'); + expect(response.body).to.have.property("data"); }); }); - it('Gets all teams that belong to a user.', () => { + it("Gets all teams that belong to a user.", () => { cy.request({ - method: 'GET', + method: "GET", url: `/api/users/${userId}/teams`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('data'); + expect(response.body).to.have.property("data"); }); }); }); diff --git a/cypress/e2e/api-website.cy.ts b/cypress/e2e/api-website.cy.ts index cd336bda0..6fc8a2118 100644 --- a/cypress/e2e/api-website.cy.ts +++ b/cypress/e2e/api-website.cy.ts @@ -1,194 +1,194 @@ -import { uuid } from '../../src/lib/crypto'; +import { uuid } from "../../src/lib/crypto"; -describe('Website API tests', () => { +describe("Website API tests", () => { Cypress.session.clearAllSavedSessions(); let websiteId; let teamId; before(() => { - cy.login(Cypress.env('umami_user'), Cypress.env('umami_password')); - cy.fixture('teams').then(data => { + cy.login(Cypress.env("syncfuse_user"), Cypress.env("syncfuse_password")); + cy.fixture("teams").then((data) => { const teamCreate = data.teamCreate; cy.request({ - method: 'POST', - url: '/api/teams', + method: "POST", + url: "/api/teams", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: teamCreate, - }).then(response => { + }).then((response) => { teamId = response.body[0].id; expect(response.status).to.eq(200); - expect(response.body[0]).to.have.property('name', 'cypress'); - expect(response.body[1]).to.have.property('role', 'team-owner'); + expect(response.body[0]).to.have.property("name", "cypress"); + expect(response.body[1]).to.have.property("role", "team-owner"); }); }); }); - it('Creates a website for user.', () => { - cy.fixture('websites').then(data => { + it("Creates a website for user.", () => { + cy.fixture("websites").then((data) => { const websiteCreate = data.websiteCreate; cy.request({ - method: 'POST', - url: '/api/websites', + method: "POST", + url: "/api/websites", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: websiteCreate, - }).then(response => { + }).then((response) => { websiteId = response.body.id; expect(response.status).to.eq(200); - expect(response.body).to.have.property('name', 'Cypress Website'); - expect(response.body).to.have.property('domain', 'cypress.com'); + expect(response.body).to.have.property("name", "Cypress Website"); + expect(response.body).to.have.property("domain", "cypress.com"); }); }); }); - it('Creates a website for team.', () => { + it("Creates a website for team.", () => { cy.request({ - method: 'POST', - url: '/api/websites', + method: "POST", + url: "/api/websites", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: { - name: 'Team Website', - domain: 'teamwebsite.com', + name: "Team Website", + domain: "teamwebsite.com", teamId: teamId, }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('name', 'Team Website'); - expect(response.body).to.have.property('domain', 'teamwebsite.com'); + expect(response.body).to.have.property("name", "Team Website"); + expect(response.body).to.have.property("domain", "teamwebsite.com"); }); }); - it('Creates a website with a fixed ID.', () => { - cy.fixture('websites').then(data => { + it("Creates a website with a fixed ID.", () => { + cy.fixture("websites").then((data) => { const websiteCreate = data.websiteCreate; const fixedId = uuid(); cy.request({ - method: 'POST', - url: '/api/websites', + method: "POST", + url: "/api/websites", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: { ...websiteCreate, id: fixedId }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('id', fixedId); - expect(response.body).to.have.property('name', 'Cypress Website'); - expect(response.body).to.have.property('domain', 'cypress.com'); + expect(response.body).to.have.property("id", fixedId); + expect(response.body).to.have.property("name", "Cypress Website"); + expect(response.body).to.have.property("domain", "cypress.com"); // cleanup cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/websites/${fixedId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, }); }); }); }); - it('Returns all tracked websites.', () => { + it("Returns all tracked websites.", () => { cy.request({ - method: 'GET', - url: '/api/websites', + method: "GET", + url: "/api/websites", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body.data[0]).to.have.property('id'); - expect(response.body.data[0]).to.have.property('name'); - expect(response.body.data[0]).to.have.property('domain'); + expect(response.body.data[0]).to.have.property("id"); + expect(response.body.data[0]).to.have.property("name"); + expect(response.body.data[0]).to.have.property("domain"); }); }); - it('Gets a website by ID.', () => { + it("Gets a website by ID.", () => { cy.request({ - method: 'GET', + method: "GET", url: `/api/websites/${websiteId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('name', 'Cypress Website'); - expect(response.body).to.have.property('domain', 'cypress.com'); + expect(response.body).to.have.property("name", "Cypress Website"); + expect(response.body).to.have.property("domain", "cypress.com"); }); }); - it('Updates a website.', () => { - cy.fixture('websites').then(data => { + it("Updates a website.", () => { + cy.fixture("websites").then((data) => { const websiteUpdate = data.websiteUpdate; cy.request({ - method: 'POST', + method: "POST", url: `/api/websites/${websiteId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: websiteUpdate, - }).then(response => { + }).then((response) => { websiteId = response.body.id; expect(response.status).to.eq(200); - expect(response.body).to.have.property('name', 'Cypress Website Updated'); - expect(response.body).to.have.property('domain', 'cypressupdated.com'); + expect(response.body).to.have.property("name", "Cypress Website Updated"); + expect(response.body).to.have.property("domain", "cypressupdated.com"); }); }); }); - it('Updates a website with only shareId.', () => { + it("Updates a website with only shareId.", () => { cy.request({ - method: 'POST', + method: "POST", url: `/api/websites/${websiteId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - body: { shareId: 'ABCDEF' }, - }).then(response => { + body: { shareId: "ABCDEF" }, + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('shareId', 'ABCDEF'); + expect(response.body).to.have.property("shareId", "ABCDEF"); }); }); - it('Resets a website by removing all data related to the website.', () => { + it("Resets a website by removing all data related to the website.", () => { cy.request({ - method: 'POST', + method: "POST", url: `/api/websites/${websiteId}/reset`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('ok', true); + expect(response.body).to.have.property("ok", true); }); }); - it('Deletes a website.', () => { + it("Deletes a website.", () => { cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/websites/${websiteId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); - expect(response.body).to.have.property('ok', true); + expect(response.body).to.have.property("ok", true); }); }); diff --git a/cypress/e2e/login.cy.ts b/cypress/e2e/login.cy.ts index 507b1b580..3530f56b4 100644 --- a/cypress/e2e/login.cy.ts +++ b/cypress/e2e/login.cy.ts @@ -1,36 +1,34 @@ -describe('Login tests', () => { +describe("Login tests", () => { beforeEach(() => { - cy.visit('/login'); + cy.visit("/login"); }); it( - 'logs user in with correct credentials and logs user out', + "logs user in with correct credentials and logs user out", { defaultCommandTimeout: 10000, }, () => { - cy.getDataTest('input-username').find('input').as('inputUsername').click(); - cy.get('@inputUsername').type(Cypress.env('umami_user'), { delay: 0 }); - cy.get('@inputUsername').click(); - cy.getDataTest('input-password') - .find('input') - .type(Cypress.env('umami_password'), { delay: 0 }); - cy.getDataTest('button-submit').click(); - cy.url().should('eq', Cypress.config().baseUrl + '/dashboard'); + cy.getDataTest("input-username").find("input").as("inputUsername").click(); + cy.get("@inputUsername").type(Cypress.env("syncfuse_user"), { delay: 0 }); + cy.get("@inputUsername").click(); + cy.getDataTest("input-password").find("input").type(Cypress.env("syncfuse_password"), { delay: 0 }); + cy.getDataTest("button-submit").click(); + cy.url().should("eq", Cypress.config().baseUrl + "/dashboard"); cy.logout(); }, ); - it('login with blank inputs or incorrect credentials', () => { - cy.getDataTest('button-submit').click(); - cy.contains(/Required/i).should('be.visible'); + it("login with blank inputs or incorrect credentials", () => { + cy.getDataTest("button-submit").click(); + cy.contains(/Required/i).should("be.visible"); - cy.getDataTest('input-username').find('input').as('inputUsername'); - cy.get('@inputUsername').click(); - cy.get('@inputUsername').type(Cypress.env('umami_user'), { delay: 0 }); - cy.get('@inputUsername').click(); - cy.getDataTest('input-password').find('input').type('wrongpassword', { delay: 0 }); - cy.getDataTest('button-submit').click(); - cy.contains(/Incorrect username and\/or password./i).should('be.visible'); + cy.getDataTest("input-username").find("input").as("inputUsername"); + cy.get("@inputUsername").click(); + cy.get("@inputUsername").type(Cypress.env("syncfuse_user"), { delay: 0 }); + cy.get("@inputUsername").click(); + cy.getDataTest("input-password").find("input").type("wrongpassword", { delay: 0 }); + cy.getDataTest("button-submit").click(); + cy.contains(/Incorrect username and\/or password./i).should("be.visible"); }); }); diff --git a/cypress/e2e/user.cy.ts b/cypress/e2e/user.cy.ts index 24df30539..7faa25540 100644 --- a/cypress/e2e/user.cy.ts +++ b/cypress/e2e/user.cy.ts @@ -1,65 +1,65 @@ -describe('User tests', () => { +describe("User tests", () => { Cypress.session.clearAllSavedSessions(); beforeEach(() => { - cy.login(Cypress.env('umami_user'), Cypress.env('umami_password')); - cy.visit('/settings/users'); + cy.login(Cypress.env("syncfuse_user"), Cypress.env("syncfuse_password")); + cy.visit("/settings/users"); }); - it('Add a User', () => { + it("Add a User", () => { // add user - cy.contains(/Create user/i).should('be.visible'); - cy.getDataTest('button-create-user').click(); - cy.getDataTest('input-username').find('input').as('inputName').click(); - cy.get('@inputName').type('Test-user', { delay: 0 }); - cy.getDataTest('input-password').find('input').as('inputPassword').click(); - cy.get('@inputPassword').type('testPasswordCypress', { delay: 0 }); - cy.getDataTest('dropdown-role').click(); - cy.getDataTest('dropdown-item-user').click(); - cy.getDataTest('button-submit').click(); - cy.get('td[label="Username"]').should('contain.text', 'Test-user'); - cy.get('td[label="Role"]').should('contain.text', 'User'); + cy.contains(/Create user/i).should("be.visible"); + cy.getDataTest("button-create-user").click(); + cy.getDataTest("input-username").find("input").as("inputName").click(); + cy.get("@inputName").type("Test-user", { delay: 0 }); + cy.getDataTest("input-password").find("input").as("inputPassword").click(); + cy.get("@inputPassword").type("testPasswordCypress", { delay: 0 }); + cy.getDataTest("dropdown-role").click(); + cy.getDataTest("dropdown-item-user").click(); + cy.getDataTest("button-submit").click(); + cy.get('td[label="Username"]').should("contain.text", "Test-user"); + cy.get('td[label="Role"]').should("contain.text", "User"); }); - it('Edit a User role and password', () => { + it("Edit a User role and password", () => { // edit user - cy.get('table tbody tr') - .contains('td', /Test-user/i) + cy.get("table tbody tr") + .contains("td", /Test-user/i) .parent() .within(() => { - cy.getDataTest('link-button-edit').click(); // Clicks the button inside the row + cy.getDataTest("link-button-edit").click(); // Clicks the button inside the row }); - cy.getDataTest('input-password').find('input').as('inputPassword').click(); - cy.get('@inputPassword').type('newPassword', { delay: 0 }); - cy.getDataTest('dropdown-role').click(); - cy.getDataTest('dropdown-item-viewOnly').click(); - cy.getDataTest('button-submit').click(); + cy.getDataTest("input-password").find("input").as("inputPassword").click(); + cy.get("@inputPassword").type("newPassword", { delay: 0 }); + cy.getDataTest("dropdown-role").click(); + cy.getDataTest("dropdown-item-viewOnly").click(); + cy.getDataTest("button-submit").click(); - cy.visit('/settings/users'); - cy.get('table tbody tr') - .contains('td', /Test-user/i) + cy.visit("/settings/users"); + cy.get("table tbody tr") + .contains("td", /Test-user/i) .parent() - .should('contain.text', 'View only'); + .should("contain.text", "View only"); cy.logout(); - cy.url().should('eq', Cypress.config().baseUrl + '/login'); - cy.getDataTest('input-username').find('input').as('inputUsername').click(); - cy.get('@inputUsername').type('Test-user', { delay: 0 }); - cy.get('@inputUsername').click(); - cy.getDataTest('input-password').find('input').type('newPassword', { delay: 0 }); - cy.getDataTest('button-submit').click(); - cy.url().should('eq', Cypress.config().baseUrl + '/dashboard'); + cy.url().should("eq", Cypress.config().baseUrl + "/login"); + cy.getDataTest("input-username").find("input").as("inputUsername").click(); + cy.get("@inputUsername").type("Test-user", { delay: 0 }); + cy.get("@inputUsername").click(); + cy.getDataTest("input-password").find("input").type("newPassword", { delay: 0 }); + cy.getDataTest("button-submit").click(); + cy.url().should("eq", Cypress.config().baseUrl + "/dashboard"); }); - it('Delete a user', () => { + it("Delete a user", () => { // delete user - cy.get('table tbody tr') - .contains('td', /Test-user/i) + cy.get("table tbody tr") + .contains("td", /Test-user/i) .parent() .within(() => { - cy.getDataTest('button-delete').click(); // Clicks the button inside the row + cy.getDataTest("button-delete").click(); // Clicks the button inside the row }); - cy.contains(/Are you sure you want to delete Test-user?/i).should('be.visible'); - cy.getDataTest('button-confirm').click(); + cy.contains(/Are you sure you want to delete Test-user?/i).should("be.visible"); + cy.getDataTest("button-confirm").click(); }); }); diff --git a/cypress/e2e/website.cy.ts b/cypress/e2e/website.cy.ts index 2dcd60273..abdf87fc0 100644 --- a/cypress/e2e/website.cy.ts +++ b/cypress/e2e/website.cy.ts @@ -1,89 +1,89 @@ -describe('Website tests', () => { +describe("Website tests", () => { Cypress.session.clearAllSavedSessions(); beforeEach(() => { - cy.login(Cypress.env('umami_user'), Cypress.env('umami_password')); + cy.login(Cypress.env("syncfuse_user"), Cypress.env("syncfuse_password")); }); - it('Add a website', () => { + it("Add a website", () => { // add website - cy.visit('/settings/websites'); - cy.getDataTest('button-website-add').click(); - cy.contains(/Add website/i).should('be.visible'); - cy.getDataTest('input-name').find('input').as('inputUsername').click(); - cy.getDataTest('input-name').find('input').type('Add test', { delay: 0 }); - cy.getDataTest('input-domain').find('input').click(); - cy.getDataTest('input-domain').find('input').type('addtest.com', { delay: 0 }); - cy.getDataTest('button-submit').click(); - cy.get('td[label="Name"]').should('contain.text', 'Add test'); - cy.get('td[label="Domain"]').should('contain.text', 'addtest.com'); + cy.visit("/settings/websites"); + cy.getDataTest("button-website-add").click(); + cy.contains(/Add website/i).should("be.visible"); + cy.getDataTest("input-name").find("input").as("inputUsername").click(); + cy.getDataTest("input-name").find("input").type("Add test", { delay: 0 }); + cy.getDataTest("input-domain").find("input").click(); + cy.getDataTest("input-domain").find("input").type("addtest.com", { delay: 0 }); + cy.getDataTest("button-submit").click(); + cy.get('td[label="Name"]').should("contain.text", "Add test"); + cy.get('td[label="Domain"]').should("contain.text", "addtest.com"); // clean-up data - cy.getDataTest('link-button-edit').first().click(); - cy.contains(/Details/i).should('be.visible'); - cy.getDataTest('text-field-websiteId') - .find('input') - .then($input => { + cy.getDataTest("link-button-edit").first().click(); + cy.contains(/Details/i).should("be.visible"); + cy.getDataTest("text-field-websiteId") + .find("input") + .then(($input) => { const websiteId = $input[0].value; cy.deleteWebsite(websiteId); }); - cy.visit('/settings/websites'); - cy.contains(/Add test/i).should('not.exist'); + cy.visit("/settings/websites"); + cy.contains(/Add test/i).should("not.exist"); }); - it('Edit a website', () => { + it("Edit a website", () => { // prep data - cy.addWebsite('Update test', 'updatetest.com'); - cy.visit('/settings/websites'); + cy.addWebsite("Update test", "updatetest.com"); + cy.visit("/settings/websites"); // edit website - cy.getDataTest('link-button-edit').first().click(); - cy.contains(/Details/i).should('be.visible'); - cy.getDataTest('input-name').find('input').click(); - cy.getDataTest('input-name').find('input').clear(); - cy.getDataTest('input-name').find('input').type('Updated website', { delay: 0 }); - cy.getDataTest('input-domain').find('input').click(); - cy.getDataTest('input-domain').find('input').clear(); - cy.getDataTest('input-domain').find('input').type('updatedwebsite.com', { delay: 0 }); - cy.getDataTest('button-submit').click({ force: true }); - cy.getDataTest('input-name').find('input').should('have.value', 'Updated website'); - cy.getDataTest('input-domain').find('input').should('have.value', 'updatedwebsite.com'); + cy.getDataTest("link-button-edit").first().click(); + cy.contains(/Details/i).should("be.visible"); + cy.getDataTest("input-name").find("input").click(); + cy.getDataTest("input-name").find("input").clear(); + cy.getDataTest("input-name").find("input").type("Updated website", { delay: 0 }); + cy.getDataTest("input-domain").find("input").click(); + cy.getDataTest("input-domain").find("input").clear(); + cy.getDataTest("input-domain").find("input").type("updatedwebsite.com", { delay: 0 }); + cy.getDataTest("button-submit").click({ force: true }); + cy.getDataTest("input-name").find("input").should("have.value", "Updated website"); + cy.getDataTest("input-domain").find("input").should("have.value", "updatedwebsite.com"); // verify tracking script - cy.get('div') + cy.get("div") .contains(/Tracking code/i) .click(); - cy.get('textarea').should('contain.text', Cypress.config().baseUrl + '/script.js'); + cy.get("textarea").should("contain.text", Cypress.config().baseUrl + "/script.js"); // clean-up data - cy.get('div') + cy.get("div") .contains(/Details/i) .click(); - cy.contains(/Details/i).should('be.visible'); - cy.getDataTest('text-field-websiteId') - .find('input') - .then($input => { + cy.contains(/Details/i).should("be.visible"); + cy.getDataTest("text-field-websiteId") + .find("input") + .then(($input) => { const websiteId = $input[0].value; cy.deleteWebsite(websiteId); }); - cy.visit('/settings/websites'); - cy.contains(/Add test/i).should('not.exist'); + cy.visit("/settings/websites"); + cy.contains(/Add test/i).should("not.exist"); }); - it('Delete a website', () => { + it("Delete a website", () => { // prep data - cy.addWebsite('Delete test', 'deletetest.com'); - cy.visit('/settings/websites'); + cy.addWebsite("Delete test", "deletetest.com"); + cy.visit("/settings/websites"); // delete website - cy.getDataTest('link-button-edit').first().click(); - cy.contains(/Data/i).should('be.visible'); - cy.get('div').contains(/Data/i).click(); - cy.contains(/All website data will be deleted./i).should('be.visible'); - cy.getDataTest('button-delete').click(); - cy.contains(/Type DELETE in the box below to confirm./i).should('be.visible'); - cy.get('input[name="confirm"').type('DELETE'); + cy.getDataTest("link-button-edit").first().click(); + cy.contains(/Data/i).should("be.visible"); + cy.get("div").contains(/Data/i).click(); + cy.contains(/All website data will be deleted./i).should("be.visible"); + cy.getDataTest("button-delete").click(); + cy.contains(/Type DELETE in the box below to confirm./i).should("be.visible"); + cy.get('input[name="confirm"').type("DELETE"); cy.get('button[type="submit"]').click(); - cy.contains(/Delete test/i).should('not.exist'); + cy.contains(/Delete test/i).should("not.exist"); }); }); diff --git a/cypress/support/e2e.ts b/cypress/support/e2e.ts index a95035ba0..887da922d 100644 --- a/cypress/support/e2e.ts +++ b/cypress/support/e2e.ts @@ -1,123 +1,123 @@ /// -import { uuid } from '../../src/lib/crypto'; +import { uuid } from "../../src/lib/crypto"; -Cypress.Commands.add('getDataTest', (value: string) => { +Cypress.Commands.add("getDataTest", (value: string) => { return cy.get(`[data-test=${value}]`); }); -Cypress.Commands.add('logout', () => { - cy.getDataTest('button-profile').click(); - cy.getDataTest('item-logout').click(); - cy.url().should('eq', Cypress.config().baseUrl + '/login'); +Cypress.Commands.add("logout", () => { + cy.getDataTest("button-profile").click(); + cy.getDataTest("item-logout").click(); + cy.url().should("eq", Cypress.config().baseUrl + "/login"); }); -Cypress.Commands.add('login', (username: string, password: string) => { +Cypress.Commands.add("login", (username: string, password: string) => { cy.session([username, password], () => { cy.request({ - method: 'POST', - url: '/api/auth/login', + method: "POST", + url: "/api/auth/login", body: { username, password, }, }) - .then(response => { - Cypress.env('authorization', `bearer ${response.body.token}`); - window.localStorage.setItem('umami.auth', JSON.stringify(response.body.token)); + .then((response) => { + Cypress.env("authorization", `bearer ${response.body.token}`); + window.localStorage.setItem("syncfuse.auth", JSON.stringify(response.body.token)); }) - .its('status') - .should('eq', 200); + .its("status") + .should("eq", 200); }); }); -Cypress.Commands.add('addWebsite', (name: string, domain: string) => { +Cypress.Commands.add("addWebsite", (name: string, domain: string) => { cy.request({ - method: 'POST', - url: '/api/websites', + method: "POST", + url: "/api/websites", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: { id: uuid(), - createdBy: '41e2b680-648e-4b09-bcd7-3e2b10c06264', + createdBy: "41e2b680-648e-4b09-bcd7-3e2b10c06264", name: name, domain: domain, }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); }); }); -Cypress.Commands.add('deleteWebsite', (websiteId: string) => { +Cypress.Commands.add("deleteWebsite", (websiteId: string) => { cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/websites/${websiteId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); }); }); -Cypress.Commands.add('addUser', (username: string, password: string, role: string) => { +Cypress.Commands.add("addUser", (username: string, password: string, role: string) => { cy.request({ - method: 'POST', - url: '/api/users', + method: "POST", + url: "/api/users", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: { username: username, password: password, role: role, }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); }); }); -Cypress.Commands.add('deleteUser', (userId: string) => { +Cypress.Commands.add("deleteUser", (userId: string) => { cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/users/${userId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); }); }); -Cypress.Commands.add('addTeam', (name: string) => { +Cypress.Commands.add("addTeam", (name: string) => { cy.request({ - method: 'POST', - url: '/api/teams', + method: "POST", + url: "/api/teams", headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, body: { name: name, }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); }); }); -Cypress.Commands.add('deleteTeam', (teamId: string) => { +Cypress.Commands.add("deleteTeam", (teamId: string) => { cy.request({ - method: 'DELETE', + method: "DELETE", url: `/api/teams/${teamId}`, headers: { - 'Content-Type': 'application/json', - Authorization: Cypress.env('authorization'), + "Content-Type": "application/json", + Authorization: Cypress.env("authorization"), }, - }).then(response => { + }).then((response) => { expect(response.status).to.eq(200); }); }); diff --git a/db/clickhouse/migrations/01_edit_keys.sql b/db/clickhouse/migrations/01_edit_keys.sql index 3fc7dd79c..ee4a3c28c 100644 --- a/db/clickhouse/migrations/01_edit_keys.sql +++ b/db/clickhouse/migrations/01_edit_keys.sql @@ -9,10 +9,10 @@ ALTER TABLE "website_event" ADD COLUMN "job_id" UUID AFTER "created_at"; ALTER TABLE "event_data" ADD COLUMN "job_id" UUID AFTER "created_at"; -- update event_data string -alter table umami.event_data +alter table syncfuse.event_data update string_value = number_value where data_type = 2 -alter table umami.event_data +alter table syncfuse.event_data update string_value = replaceOne(concat(CAST(toDateTime(date_value, 'UTC'), 'String'),'Z'), ' ', 'T') where data_type = 4 \ No newline at end of file diff --git a/db/clickhouse/migrations/02_add_visit_id.sql b/db/clickhouse/migrations/02_add_visit_id.sql index 202c0fd30..547b686e1 100644 --- a/db/clickhouse/migrations/02_add_visit_id.sql +++ b/db/clickhouse/migrations/02_add_visit_id.sql @@ -1,4 +1,4 @@ -CREATE TABLE umami.website_event_join +CREATE TABLE syncfuse.website_event_join ( session_id UUID, visit_id UUID, @@ -8,7 +8,7 @@ CREATE TABLE umami.website_event_join ORDER BY (session_id, created_at) SETTINGS index_granularity = 8192; -INSERT INTO umami.website_event_join +INSERT INTO syncfuse.website_event_join SELECT DISTINCT s.session_id, generateUUIDv4() visit_id, @@ -18,7 +18,7 @@ FROM (SELECT DISTINCT session_id, FROM website_event) s; -- create new table -CREATE TABLE umami.website_event_new +CREATE TABLE syncfuse.website_event_new ( website_id UUID, session_id UUID, @@ -49,7 +49,7 @@ CREATE TABLE umami.website_event_new ORDER BY (website_id, session_id, created_at) SETTINGS index_granularity = 8192; -INSERT INTO umami.website_event_new +INSERT INTO syncfuse.website_event_new SELECT we.website_id, we.session_id, j.visit_id, @@ -74,17 +74,17 @@ SELECT we.website_id, we.event_name, we.created_at, we.job_id -FROM umami.website_event we -JOIN umami.website_event_join j +FROM syncfuse.website_event we +JOIN syncfuse.website_event_join j ON we.session_id = j.session_id and date_trunc('hour', we.created_at) = j.created_at -RENAME TABLE umami.website_event TO umami.website_event_old; -RENAME TABLE umami.website_event_new TO umami.website_event; +RENAME TABLE syncfuse.website_event TO syncfuse.website_event_old; +RENAME TABLE syncfuse.website_event_new TO syncfuse.website_event; /* - DROP TABLE umami.website_event_old - DROP TABLE umami.website_event_join + DROP TABLE syncfuse.website_event_old + DROP TABLE syncfuse.website_event_join */ \ No newline at end of file diff --git a/db/clickhouse/migrations/03_session_data.sql b/db/clickhouse/migrations/03_session_data.sql index 1ed2c060e..1a3ae27d1 100644 --- a/db/clickhouse/migrations/03_session_data.sql +++ b/db/clickhouse/migrations/03_session_data.sql @@ -1,4 +1,4 @@ -CREATE TABLE umami.event_data_new +CREATE TABLE syncfuse.event_data_new ( website_id UUID, session_id UUID, @@ -17,7 +17,7 @@ CREATE TABLE umami.event_data_new ORDER BY (website_id, event_id, data_key, created_at) SETTINGS index_granularity = 8192; -INSERT INTO umami.event_data_new +INSERT INTO syncfuse.event_data_new SELECT website_id, session_id, event_id, @@ -30,9 +30,9 @@ SELECT website_id, data_type, created_at, NULL -FROM umami.event_data; +FROM syncfuse.event_data; -CREATE TABLE umami.session_data +CREATE TABLE syncfuse.session_data ( website_id UUID, session_id UUID, @@ -48,10 +48,10 @@ CREATE TABLE umami.session_data ORDER BY (website_id, session_id, data_key, created_at) SETTINGS index_granularity = 8192; -RENAME TABLE umami.event_data TO umami.event_data_old; -RENAME TABLE umami.event_data_new TO umami.event_data; +RENAME TABLE syncfuse.event_data TO syncfuse.event_data_old; +RENAME TABLE syncfuse.event_data_new TO syncfuse.event_data; /* -DROP TABLE umami.event_data_old +DROP TABLE syncfuse.event_data_old */ diff --git a/db/clickhouse/migrations/04_add_tag.sql b/db/clickhouse/migrations/04_add_tag.sql index 7ffc49952..d81806824 100644 --- a/db/clickhouse/migrations/04_add_tag.sql +++ b/db/clickhouse/migrations/04_add_tag.sql @@ -1,12 +1,12 @@ -- 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"; +ALTER TABLE syncfuse.website_event ADD COLUMN "tag" String AFTER "event_name"; +ALTER TABLE syncfuse.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; +DROP TABLE syncfuse.website_event_stats_hourly_mv; -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv -TO umami.website_event_stats_hourly +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv +TO syncfuse.website_event_stats_hourly AS SELECT website_id, @@ -60,7 +60,7 @@ FROM (SELECT max(created_at) max_time, arrayFilter(x -> x != '', groupArray(tag)) tag, toStartOfHour(created_at) timestamp -FROM umami.website_event +FROM syncfuse.website_event GROUP BY website_id, session_id, visit_id, diff --git a/db/clickhouse/migrations/05_add_utm_clid.sql b/db/clickhouse/migrations/05_add_utm_clid.sql index 30d9671d5..d98f66411 100644 --- a/db/clickhouse/migrations/05_add_utm_clid.sql +++ b/db/clickhouse/migrations/05_add_utm_clid.sql @@ -1,5 +1,5 @@ -- Create Event -CREATE TABLE umami.website_event_new +CREATE TABLE syncfuse.website_event_new ( website_id UUID, session_id UUID, @@ -49,7 +49,7 @@ ENGINE = MergeTree SETTINGS index_granularity = 8192; -- stats hourly -CREATE TABLE umami.website_event_stats_hourly_new +CREATE TABLE syncfuse.website_event_stats_hourly_new ( website_id UUID, session_id UUID, @@ -99,8 +99,8 @@ ENGINE = AggregatingMergeTree ) SAMPLE BY cityHash64(visit_id); -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv_new -TO umami.website_event_stats_hourly_new +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv_new +TO syncfuse.website_event_stats_hourly_new AS SELECT website_id, @@ -176,7 +176,7 @@ FROM (SELECT max(created_at) max_time, arrayFilter(x -> x != '', groupArray(tag)) tag, toStartOfHour(created_at) timestamp -FROM umami.website_event_new +FROM syncfuse.website_event_new GROUP BY website_id, session_id, visit_id, @@ -193,22 +193,22 @@ GROUP BY website_id, timestamp); -- projections -ALTER TABLE umami.website_event_new +ALTER TABLE syncfuse.website_event_new ADD PROJECTION website_event_url_path_projection ( SELECT * ORDER BY toStartOfDay(created_at), website_id, url_path, created_at ); -ALTER TABLE umami.website_event_new MATERIALIZE PROJECTION website_event_url_path_projection; +ALTER TABLE syncfuse.website_event_new MATERIALIZE PROJECTION website_event_url_path_projection; -ALTER TABLE umami.website_event_new +ALTER TABLE syncfuse.website_event_new ADD PROJECTION website_event_referrer_domain_projection ( SELECT * ORDER BY toStartOfDay(created_at), website_id, referrer_domain, created_at ); -ALTER TABLE umami.website_event_new MATERIALIZE PROJECTION website_event_referrer_domain_projection; +ALTER TABLE syncfuse.website_event_new MATERIALIZE PROJECTION website_event_referrer_domain_projection; -- migration -INSERT INTO umami.website_event_new +INSERT INTO syncfuse.website_event_new SELECT website_id, session_id, visit_id, event_id, hostname, browser, os, device, screen, language, country, subdivision1, subdivision2, city, url_path, url_query, extract(url_query, 'utm_source=([^&]*)') AS utm_source, extract(url_query, 'utm_medium=([^&]*)') AS utm_medium, @@ -223,23 +223,23 @@ SELECT website_id, session_id, visit_id, event_id, hostname, browser, os, device extract(url_query, 'li_fat_id=([^&]*)') li_fat_id, extract(url_query, 'twclid=([^&]*)') twclid, event_type, event_name, tag, created_at, job_id -FROM umami.website_event +FROM syncfuse.website_event -- rename tables -RENAME TABLE umami.website_event TO umami.website_event_old; -RENAME TABLE umami.website_event_new TO umami.website_event; +RENAME TABLE syncfuse.website_event TO syncfuse.website_event_old; +RENAME TABLE syncfuse.website_event_new TO syncfuse.website_event; -RENAME TABLE umami.website_event_stats_hourly TO umami.website_event_stats_hourly_old; -RENAME TABLE umami.website_event_stats_hourly_new TO umami.website_event_stats_hourly; +RENAME TABLE syncfuse.website_event_stats_hourly TO syncfuse.website_event_stats_hourly_old; +RENAME TABLE syncfuse.website_event_stats_hourly_new TO syncfuse.website_event_stats_hourly; -RENAME TABLE umami.website_event_stats_hourly_mv TO umami.website_event_stats_hourly_mv_old; -RENAME TABLE umami.website_event_stats_hourly_mv_new TO umami.website_event_stats_hourly_mv; +RENAME TABLE syncfuse.website_event_stats_hourly_mv TO syncfuse.website_event_stats_hourly_mv_old; +RENAME TABLE syncfuse.website_event_stats_hourly_mv_new TO syncfuse.website_event_stats_hourly_mv; -- recreate view -DROP TABLE umami.website_event_stats_hourly_mv; +DROP TABLE syncfuse.website_event_stats_hourly_mv; -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv -TO umami.website_event_stats_hourly +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv +TO syncfuse.website_event_stats_hourly AS SELECT website_id, @@ -315,7 +315,7 @@ FROM (SELECT max(created_at) max_time, arrayFilter(x -> x != '', groupArray(tag)) tag, toStartOfHour(created_at) timestamp -FROM umami.website_event +FROM syncfuse.website_event GROUP BY website_id, session_id, visit_id, diff --git a/db/clickhouse/migrations/06_update_subdivision.sql b/db/clickhouse/migrations/06_update_subdivision.sql index 70f4ba481..f48ea84eb 100644 --- a/db/clickhouse/migrations/06_update_subdivision.sql +++ b/db/clickhouse/migrations/06_update_subdivision.sql @@ -1,35 +1,35 @@ -- drop projections -ALTER TABLE umami.website_event DROP PROJECTION website_event_url_path_projection; -ALTER TABLE umami.website_event DROP PROJECTION website_event_referrer_domain_projection; +ALTER TABLE syncfuse.website_event DROP PROJECTION website_event_url_path_projection; +ALTER TABLE syncfuse.website_event DROP PROJECTION website_event_referrer_domain_projection; --drop view -DROP TABLE umami.website_event_stats_hourly_mv; +DROP TABLE syncfuse.website_event_stats_hourly_mv; -- rename columns -ALTER TABLE umami.website_event RENAME COLUMN "subdivision1" TO "region"; -ALTER TABLE umami.website_event_stats_hourly RENAME COLUMN "subdivision1" TO "region"; +ALTER TABLE syncfuse.website_event RENAME COLUMN "subdivision1" TO "region"; +ALTER TABLE syncfuse.website_event_stats_hourly RENAME COLUMN "subdivision1" TO "region"; -- drop columns -ALTER TABLE umami.website_event DROP COLUMN "subdivision2"; +ALTER TABLE syncfuse.website_event DROP COLUMN "subdivision2"; -- recreate projections -ALTER TABLE umami.website_event +ALTER TABLE syncfuse.website_event ADD PROJECTION website_event_url_path_projection ( SELECT * ORDER BY toStartOfDay(created_at), website_id, url_path, created_at ); -ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_url_path_projection; +ALTER TABLE syncfuse.website_event MATERIALIZE PROJECTION website_event_url_path_projection; -ALTER TABLE umami.website_event +ALTER TABLE syncfuse.website_event ADD PROJECTION website_event_referrer_domain_projection ( SELECT * ORDER BY toStartOfDay(created_at), website_id, referrer_domain, created_at ); -ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_referrer_domain_projection; +ALTER TABLE syncfuse.website_event MATERIALIZE PROJECTION website_event_referrer_domain_projection; -- recreate view -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv -TO umami.website_event_stats_hourly +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv +TO syncfuse.website_event_stats_hourly AS SELECT website_id, @@ -105,7 +105,7 @@ FROM (SELECT max(created_at) max_time, arrayFilter(x -> x != '', groupArray(tag)) tag, toStartOfHour(created_at) timestamp -FROM umami.website_event +FROM syncfuse.website_event GROUP BY website_id, session_id, visit_id, diff --git a/db/clickhouse/migrations/07_add_distinct_id.sql b/db/clickhouse/migrations/07_add_distinct_id.sql index e2356940d..0930f27df 100644 --- a/db/clickhouse/migrations/07_add_distinct_id.sql +++ b/db/clickhouse/migrations/07_add_distinct_id.sql @@ -1,13 +1,13 @@ -- add tag column -ALTER TABLE umami.website_event ADD COLUMN "distinct_id" String AFTER "tag"; -ALTER TABLE umami.website_event_stats_hourly ADD COLUMN "distinct_id" String AFTER "tag"; -ALTER TABLE umami.session_data ADD COLUMN "distinct_id" String AFTER "data_type"; +ALTER TABLE syncfuse.website_event ADD COLUMN "distinct_id" String AFTER "tag"; +ALTER TABLE syncfuse.website_event_stats_hourly ADD COLUMN "distinct_id" String AFTER "tag"; +ALTER TABLE syncfuse.session_data ADD COLUMN "distinct_id" String AFTER "data_type"; -- update materialized view -DROP TABLE umami.website_event_stats_hourly_mv; +DROP TABLE syncfuse.website_event_stats_hourly_mv; -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv -TO umami.website_event_stats_hourly +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv +TO syncfuse.website_event_stats_hourly AS SELECT website_id, @@ -85,7 +85,7 @@ FROM (SELECT arrayFilter(x -> x != '', groupArray(tag)) tag, distinct_id, toStartOfHour(created_at) timestamp -FROM umami.website_event +FROM syncfuse.website_event GROUP BY website_id, session_id, visit_id, diff --git a/db/clickhouse/migrations/08_update_hostname_view.sql b/db/clickhouse/migrations/08_update_hostname_view.sql index 061fa6285..aa2572d96 100644 --- a/db/clickhouse/migrations/08_update_hostname_view.sql +++ b/db/clickhouse/migrations/08_update_hostname_view.sql @@ -1,5 +1,5 @@ -- create new hourly table -CREATE TABLE umami.website_event_stats_hourly_new +CREATE TABLE syncfuse.website_event_stats_hourly_new ( website_id UUID, session_id UUID, @@ -51,8 +51,8 @@ ENGINE = AggregatingMergeTree SAMPLE BY cityHash64(visit_id); -- create view -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv_new -TO umami.website_event_stats_hourly_new +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv_new +TO syncfuse.website_event_stats_hourly_new AS SELECT website_id, @@ -130,7 +130,7 @@ FROM (SELECT arrayFilter(x -> x != '', groupArray(tag)) tag, distinct_id, toStartOfHour(created_at) timestamp -FROM umami.website_event +FROM syncfuse.website_event GROUP BY website_id, session_id, visit_id, @@ -148,16 +148,16 @@ GROUP BY website_id, timestamp); -- rename tables -RENAME TABLE umami.website_event_stats_hourly TO umami.website_event_stats_hourly_old; -RENAME TABLE umami.website_event_stats_hourly_new TO umami.website_event_stats_hourly; +RENAME TABLE syncfuse.website_event_stats_hourly TO syncfuse.website_event_stats_hourly_old; +RENAME TABLE syncfuse.website_event_stats_hourly_new TO syncfuse.website_event_stats_hourly; -- drop views -DROP TABLE umami.website_event_stats_hourly_mv; -DROP TABLE umami.website_event_stats_hourly_mv_new; +DROP TABLE syncfuse.website_event_stats_hourly_mv; +DROP TABLE syncfuse.website_event_stats_hourly_mv_new; -- recreate view -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv -TO umami.website_event_stats_hourly +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv +TO syncfuse.website_event_stats_hourly AS SELECT website_id, @@ -235,7 +235,7 @@ FROM (SELECT arrayFilter(x -> x != '', groupArray(tag)) tag, distinct_id, toStartOfHour(created_at) timestamp -FROM umami.website_event +FROM syncfuse.website_event GROUP BY website_id, session_id, visit_id, diff --git a/db/clickhouse/schema.sql b/db/clickhouse/schema.sql index e9160329e..cf3cc331e 100644 --- a/db/clickhouse/schema.sql +++ b/db/clickhouse/schema.sql @@ -1,5 +1,5 @@ -- Create Event -CREATE TABLE umami.website_event +CREATE TABLE syncfuse.website_event ( website_id UUID, session_id UUID, @@ -48,7 +48,7 @@ ENGINE = MergeTree PRIMARY KEY (toStartOfHour(created_at), website_id, session_id, visit_id) SETTINGS index_granularity = 8192; -CREATE TABLE umami.event_data +CREATE TABLE syncfuse.event_data ( website_id UUID, session_id UUID, @@ -67,7 +67,7 @@ ENGINE = MergeTree ORDER BY (website_id, event_id, data_key, created_at) SETTINGS index_granularity = 8192; -CREATE TABLE umami.session_data +CREATE TABLE syncfuse.session_data ( website_id UUID, session_id UUID, @@ -85,7 +85,7 @@ ENGINE = ReplacingMergeTree SETTINGS index_granularity = 8192; -- stats hourly -CREATE TABLE umami.website_event_stats_hourly +CREATE TABLE syncfuse.website_event_stats_hourly ( website_id UUID, session_id UUID, @@ -136,8 +136,8 @@ ENGINE = AggregatingMergeTree ) SAMPLE BY cityHash64(visit_id); -CREATE MATERIALIZED VIEW umami.website_event_stats_hourly_mv -TO umami.website_event_stats_hourly +CREATE MATERIALIZED VIEW syncfuse.website_event_stats_hourly_mv +TO syncfuse.website_event_stats_hourly AS SELECT website_id, @@ -215,7 +215,7 @@ FROM (SELECT arrayFilter(x -> x != '', groupArray(tag)) tag, distinct_id, toStartOfHour(created_at) timestamp -FROM umami.website_event +FROM syncfuse.website_event GROUP BY website_id, session_id, visit_id, @@ -233,22 +233,22 @@ GROUP BY website_id, timestamp); -- projections -ALTER TABLE umami.website_event +ALTER TABLE syncfuse.website_event ADD PROJECTION website_event_url_path_projection ( SELECT * ORDER BY toStartOfDay(created_at), website_id, url_path, created_at ); -ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_url_path_projection; +ALTER TABLE syncfuse.website_event MATERIALIZE PROJECTION website_event_url_path_projection; -ALTER TABLE umami.website_event +ALTER TABLE syncfuse.website_event ADD PROJECTION website_event_referrer_domain_projection ( SELECT * ORDER BY toStartOfDay(created_at), website_id, referrer_domain, created_at ); -ALTER TABLE umami.website_event MATERIALIZE PROJECTION website_event_referrer_domain_projection; +ALTER TABLE syncfuse.website_event MATERIALIZE PROJECTION website_event_referrer_domain_projection; -- revenue -CREATE TABLE umami.website_revenue +CREATE TABLE syncfuse.website_revenue ( website_id UUID, session_id UUID, @@ -264,8 +264,8 @@ ENGINE = MergeTree SETTINGS index_granularity = 8192; -CREATE MATERIALIZED VIEW umami.website_revenue_mv -TO umami.website_revenue +CREATE MATERIALIZED VIEW syncfuse.website_revenue_mv +TO syncfuse.website_revenue AS SELECT DISTINCT ed.website_id, @@ -275,9 +275,9 @@ SELECT DISTINCT c.currency, coalesce(toDecimal64(ed.number_value, 2), toDecimal64(ed.string_value, 2)) revenue, ed.created_at -FROM umami.event_data ed +FROM syncfuse.event_data ed JOIN (SELECT event_id, string_value as currency - FROM umami.event_data + FROM syncfuse.event_data WHERE positionCaseInsensitive(data_key, 'currency') > 0) c ON c.event_id = ed.event_id WHERE positionCaseInsensitive(data_key, 'revenue') > 0; diff --git a/docker-compose.yml b/docker-compose.yml index 348c294ca..1dc65ce99 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,11 +1,11 @@ --- services: - umami: + syncfuse: image: ghcr.io/umami-software/umami:latest ports: - "3000:3000" environment: - DATABASE_URL: postgresql://umami:umami@db:5432/umami + DATABASE_URL: postgresql://syncfuse:syncfuse@db:5432/syncfuse APP_SECRET: replace-me-with-a-random-string depends_on: db: @@ -20,11 +20,11 @@ services: db: image: postgres:15-alpine environment: - POSTGRES_DB: umami - POSTGRES_USER: umami - POSTGRES_PASSWORD: umami + POSTGRES_DB: syncfuse + POSTGRES_USER: syncfuse + POSTGRES_PASSWORD: syncfuse volumes: - - umami-db-data:/var/lib/postgresql/data + - syncfuse-db-data:/var/lib/postgresql/data restart: always healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] @@ -32,4 +32,4 @@ services: timeout: 5s retries: 5 volumes: - umami-db-data: + syncfuse-db-data: diff --git a/package.components.json b/package.components.json index ab3454c07..d1f10efd0 100644 --- a/package.components.json +++ b/package.components.json @@ -1,7 +1,7 @@ { - "name": "@umami/components", + "name": "@syncfuse/components", "version": "0.130.0", - "description": "Umami React components.", + "description": "Syncfuse React components.", "author": "Mike Cao ", "license": "MIT", "type": "module", diff --git a/package.json b/package.json index 76b1e1fa9..542d7fd2b 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,8 @@ { - "name": "umami", + "name": "syncfuse", "version": "3.0.3", "description": "A modern, privacy-focused alternative to Google Analytics.", - "author": "Umami Software, Inc. ", + "author": "Syncfuse Analytics", "license": "MIT", "homepage": "https://umami.is", "repository": { diff --git a/podman/README.md b/podman/README.md index 92d030aff..8771d1841 100644 --- a/podman/README.md +++ b/podman/README.md @@ -1,25 +1,22 @@ -# How to deploy umami on podman - +# How to deploy syncfuse on podman ## How to use 1. Rename `env.sample` to `.env` 2. Edit `.env` file. At the minimum set the passwords. -3. Start umami by running `podman-compose up -d`. - -If you need to stop umami, you can do so by running `podman-compose down`. +3. Start syncfuse by running `podman-compose up -d`. +If you need to stop syncfuse, you can do so by running `podman-compose down`. ### Install systemd service (optional) -If you want to install a systemd service to run umami, you can use the provided +If you want to install a systemd service to run syncfuse, you can use the provided systemd service. -Edit `umami.service` and change these two variables: +Edit `syncfuse.service` and change these two variables: - - WorkingDirectory=/opt/apps/umami - EnvironmentFile=/opt/apps/umami/.env + WorkingDirectory=/opt/apps/syncfuse + EnvironmentFile=/opt/apps/syncfuse/.env `WorkingDirectory` should be changed to the path in which `podman-compose.yml` is located. @@ -30,16 +27,13 @@ located. You can run the script `install-systemd-user-service` to install the systemd service under the current user. - - ./install-systemd-user-service + ./install-systemd-user-service Note: this script will enable the service and also start it. So it will assume -that umami is not currently running. If you started it previously, bring it +that syncfuse is not currently running. If you started it previously, bring it down using: - podman-compose down - - + podman-compose down ## Compatibility diff --git a/podman/env.sample b/podman/env.sample index 06435e56b..465b0743f 100644 --- a/podman/env.sample +++ b/podman/env.sample @@ -1,16 +1,16 @@ # Rename this file to .env and modify the values # -# Connection string for Umami’s database. +# Connection string for Syncfuse's database. # If you use the bundled DB container, "db" is the hostname. -DATABASE_URL=postgresql://umami:replace-me-with-a-random-string@db:5432/umami +DATABASE_URL=postgresql://syncfuse:replace-me-with-a-random-string@db:5432/syncfuse # Database type (e.g. postgresql) DATABASE_TYPE=postgresql -# A secret string used by Umami (replace with a strong random string) +# A secret string used by Syncfuse (replace with a strong random string) APP_SECRET=replace-me-with-a-random-string # Postgres container defaults. -POSTGRES_DB=umami -POSTGRES_USER=umami +POSTGRES_DB=syncfuse +POSTGRES_USER=syncfuse POSTGRES_PASSWORD=replace-me-with-a-random-string diff --git a/podman/install-systemd-user-service b/podman/install-systemd-user-service index 948a04cea..e80e3cb2c 100755 --- a/podman/install-systemd-user-service +++ b/podman/install-systemd-user-service @@ -1,6 +1,6 @@ #!/bin/bash set -e -service_name="umami" +service_name="syncfuse" mkdir -p ~/.config/systemd/user cp $service_name.service ~/.config/systemd/user diff --git a/podman/podman-compose.yml b/podman/podman-compose.yml index fcd4b3aac..135e96fe8 100644 --- a/podman/podman-compose.yml +++ b/podman/podman-compose.yml @@ -1,8 +1,8 @@ version: "3.8" services: - umami: - container_name: umami + syncfuse: + container_name: syncfuse image: ghcr.io/umami-software/umami:postgresql-latest ports: - "127.0.0.1:3000:3000" @@ -22,14 +22,14 @@ services: retries: 5 db: - container_name: umami-db + container_name: syncfuse-db image: docker.io/library/postgres:15-alpine environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - - umami-db-data:/var/lib/postgresql/data:Z + - syncfuse-db-data:/var/lib/postgresql/data:Z restart: always healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] diff --git a/podman/syncfuse.service b/podman/syncfuse.service new file mode 100644 index 000000000..f4fca6e49 --- /dev/null +++ b/podman/syncfuse.service @@ -0,0 +1,14 @@ +[Unit] +Description=Syncfuse Container Stack via Podman-Compose +After=network.target + +[Service] +Type=simple +WorkingDirectory=/opt/apps/syncfuse +EnvironmentFile=/opt/apps/syncfuse/.env +ExecStart=/usr/bin/podman-compose -f podman-compose.yml up -d +ExecStop=/usr/bin/podman-compose -f podman-compose.yml down +RemainAfterExit=yes + +[Install] +WantedBy=default.target diff --git a/public/intl/messages/am-ET.json b/public/intl/messages/am-ET.json index e0332ae05..f30506668 100644 --- a/public/intl/messages/am-ET.json +++ b/public/intl/messages/am-ET.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1990,7 +1990,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ar-SA.json b/public/intl/messages/ar-SA.json index 66a88dfb1..414035ec1 100644 --- a/public/intl/messages/ar-SA.json +++ b/public/intl/messages/ar-SA.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "إصدار جديد من Umami " + "value": "إصدار جديد من Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/be-BY.json b/public/intl/messages/be-BY.json index dc6afb79c..5eb04700a 100644 --- a/public/intl/messages/be-BY.json +++ b/public/intl/messages/be-BY.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Даступная новая версія Umami " + "value": "Даступная новая версія Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/bg-BG.json b/public/intl/messages/bg-BG.json index 1ff2a7b7e..eafa6999c 100644 --- a/public/intl/messages/bg-BG.json +++ b/public/intl/messages/bg-BG.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Има нова версия на Umami " + "value": "Има нова версия на Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/bn-BD.json b/public/intl/messages/bn-BD.json index aa66cd852..81025023a 100644 --- a/public/intl/messages/bn-BD.json +++ b/public/intl/messages/bn-BD.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2004,7 +2004,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/bs-BA.json b/public/intl/messages/bs-BA.json index 7d115a59b..f668f09fb 100644 --- a/public/intl/messages/bs-BA.json +++ b/public/intl/messages/bs-BA.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Nova verzija Umami " + "value": "Nova verzija Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ca-ES.json b/public/intl/messages/ca-ES.json index fab208b9c..1f79070af 100644 --- a/public/intl/messages/ca-ES.json +++ b/public/intl/messages/ca-ES.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Una nova versió d'Umami " + "value": "Una nova versió d'Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/cs-CZ.json b/public/intl/messages/cs-CZ.json index d45ef5dfa..1b5eab6ee 100644 --- a/public/intl/messages/cs-CZ.json +++ b/public/intl/messages/cs-CZ.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/da-DK.json b/public/intl/messages/da-DK.json index 577d06983..e96db88dd 100644 --- a/public/intl/messages/da-DK.json +++ b/public/intl/messages/da-DK.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/de-CH.json b/public/intl/messages/de-CH.json index 58d318c09..069d41442 100644 --- a/public/intl/messages/de-CH.json +++ b/public/intl/messages/de-CH.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Es isch en neue Version vo Umami " + "value": "Es isch en neue Version vo Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/de-DE.json b/public/intl/messages/de-DE.json index c78dcf5c9..358ae3e96 100644 --- a/public/intl/messages/de-DE.json +++ b/public/intl/messages/de-DE.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Eine neue Version von Umami ist verfügbar: " + "value": "Eine neue Version von Syncfuse ist verfügbar: " }, { "type": 1, diff --git a/public/intl/messages/el-GR.json b/public/intl/messages/el-GR.json index f43e2fd34..735f80e0a 100644 --- a/public/intl/messages/el-GR.json +++ b/public/intl/messages/el-GR.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/en-GB.json b/public/intl/messages/en-GB.json index 406a1ee0c..d3a1ed611 100644 --- a/public/intl/messages/en-GB.json +++ b/public/intl/messages/en-GB.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/en-US.json b/public/intl/messages/en-US.json index cdb78cd4e..64245c8f9 100644 --- a/public/intl/messages/en-US.json +++ b/public/intl/messages/en-US.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/es-ES.json b/public/intl/messages/es-ES.json index cde98b243..43c05d1a0 100644 --- a/public/intl/messages/es-ES.json +++ b/public/intl/messages/es-ES.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2002,7 +2002,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Una nueva versión de Umami " + "value": "Una nueva versión de Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/es-MX.json b/public/intl/messages/es-MX.json index 9dc4b4c96..25f76f12e 100644 --- a/public/intl/messages/es-MX.json +++ b/public/intl/messages/es-MX.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1288,7 +1288,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/fa-IR.json b/public/intl/messages/fa-IR.json index 7610a7b56..19f644a83 100644 --- a/public/intl/messages/fa-IR.json +++ b/public/intl/messages/fa-IR.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1984,7 +1984,7 @@ "message.new-version-available": [ { "type": 0, - "value": "نسخه‌ی جدیدی از Umami " + "value": "نسخه‌ی جدیدی از Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/fi-FI.json b/public/intl/messages/fi-FI.json index 7e2b92ffa..b33d71278 100644 --- a/public/intl/messages/fi-FI.json +++ b/public/intl/messages/fi-FI.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/fo-FO.json b/public/intl/messages/fo-FO.json index 9c0482632..b6163f44b 100644 --- a/public/intl/messages/fo-FO.json +++ b/public/intl/messages/fo-FO.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/fr-FR.json b/public/intl/messages/fr-FR.json index d190ec14d..66dc8a34c 100644 --- a/public/intl/messages/fr-FR.json +++ b/public/intl/messages/fr-FR.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1988,7 +1988,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Une nouvelle version d'Umami " + "value": "Une nouvelle version d'Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ga-ES.json b/public/intl/messages/ga-ES.json index d0e3d52df..865ddd6e7 100644 --- a/public/intl/messages/ga-ES.json +++ b/public/intl/messages/ga-ES.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2004,7 +2004,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Unha nova versión de Umami " + "value": "Unha nova versión de Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/he-IL.json b/public/intl/messages/he-IL.json index 8c73d0ffc..d77d458f0 100644 --- a/public/intl/messages/he-IL.json +++ b/public/intl/messages/he-IL.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1984,7 +1984,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/hi-IN.json b/public/intl/messages/hi-IN.json index 493ff994e..8c5b2c913 100644 --- a/public/intl/messages/hi-IN.json +++ b/public/intl/messages/hi-IN.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/hr-HR.json b/public/intl/messages/hr-HR.json index a6ad75039..72eb7f864 100644 --- a/public/intl/messages/hr-HR.json +++ b/public/intl/messages/hr-HR.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/hu-HU.json b/public/intl/messages/hu-HU.json index 3a228f8a9..afa30313b 100644 --- a/public/intl/messages/hu-HU.json +++ b/public/intl/messages/hu-HU.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2000,7 +2000,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/id-ID.json b/public/intl/messages/id-ID.json index 1dad7406f..6855dbc9e 100644 --- a/public/intl/messages/id-ID.json +++ b/public/intl/messages/id-ID.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1960,7 +1960,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Versi baru dari Umami " + "value": "Versi baru dari Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/it-IT.json b/public/intl/messages/it-IT.json index 40cac07ad..b9711d5e9 100644 --- a/public/intl/messages/it-IT.json +++ b/public/intl/messages/it-IT.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2000,7 +2000,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ja-JP.json b/public/intl/messages/ja-JP.json index 9b7b2e77a..745bc8368 100644 --- a/public/intl/messages/ja-JP.json +++ b/public/intl/messages/ja-JP.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1980,7 +1980,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Umamiの新しいバージョン" + "value": "Syncfuseの新しいバージョン" }, { "type": 1, diff --git a/public/intl/messages/km-KH.json b/public/intl/messages/km-KH.json index d769a8638..3660b13c8 100644 --- a/public/intl/messages/km-KH.json +++ b/public/intl/messages/km-KH.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1972,7 +1972,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Version ថ្មីនៃ Umami " + "value": "Version ថ្មីនៃ Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ko-KR.json b/public/intl/messages/ko-KR.json index 239aa6c1d..14d517f9e 100644 --- a/public/intl/messages/ko-KR.json +++ b/public/intl/messages/ko-KR.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1936,7 +1936,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Umami의 새 버전 " + "value": "Syncfuse의 새 버전 " }, { "type": 1, diff --git a/public/intl/messages/lt-LT.json b/public/intl/messages/lt-LT.json index c71d6755b..d623f2d0f 100644 --- a/public/intl/messages/lt-LT.json +++ b/public/intl/messages/lt-LT.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2121,7 +2121,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Išleista nauja 'Umami' " + "value": "Išleista nauja 'Syncfuse' " }, { "type": 1, diff --git a/public/intl/messages/mn-MN.json b/public/intl/messages/mn-MN.json index dcc965c49..eb71c960b 100644 --- a/public/intl/messages/mn-MN.json +++ b/public/intl/messages/mn-MN.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2004,7 +2004,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Umami-н шинэ хувилбар " + "value": "Syncfuse-н шинэ хувилбар " }, { "type": 1, diff --git a/public/intl/messages/ms-MY.json b/public/intl/messages/ms-MY.json index a2fdd5bbf..6c9e5444d 100644 --- a/public/intl/messages/ms-MY.json +++ b/public/intl/messages/ms-MY.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1988,7 +1988,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/my-MM.json b/public/intl/messages/my-MM.json index 74c9909ca..be52a58af 100644 --- a/public/intl/messages/my-MM.json +++ b/public/intl/messages/my-MM.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, diff --git a/public/intl/messages/nb-NO.json b/public/intl/messages/nb-NO.json index 34f7c97f9..0eefb2dd3 100644 --- a/public/intl/messages/nb-NO.json +++ b/public/intl/messages/nb-NO.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2000,7 +2000,7 @@ "message.new-version-available": [ { "type": 0, - "value": "En ny versjon av Umami " + "value": "En ny versjon av Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/nl-NL.json b/public/intl/messages/nl-NL.json index 1c136666b..649ff5645 100644 --- a/public/intl/messages/nl-NL.json +++ b/public/intl/messages/nl-NL.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Een nieuwe versie van Umami " + "value": "Een nieuwe versie van Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/pl-PL.json b/public/intl/messages/pl-PL.json index 907896416..5101e8509 100644 --- a/public/intl/messages/pl-PL.json +++ b/public/intl/messages/pl-PL.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Nowa wersja Umami " + "value": "Nowa wersja Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/pt-BR.json b/public/intl/messages/pt-BR.json index d99a3325c..931a10ccb 100644 --- a/public/intl/messages/pt-BR.json +++ b/public/intl/messages/pt-BR.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1984,7 +1984,7 @@ }, { "type": 0, - "value": " do Umami está disponível!" + "value": " do Syncfuse está disponível!" } ], "message.no-data-available": [ diff --git a/public/intl/messages/pt-PT.json b/public/intl/messages/pt-PT.json index 630b8a9f2..cf10a7baf 100644 --- a/public/intl/messages/pt-PT.json +++ b/public/intl/messages/pt-PT.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2000,7 +2000,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ro-RO.json b/public/intl/messages/ro-RO.json index d434c0b59..14b0e8cde 100644 --- a/public/intl/messages/ro-RO.json +++ b/public/intl/messages/ro-RO.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "O nouă versiune de Umami " + "value": "O nouă versiune de Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ru-RU.json b/public/intl/messages/ru-RU.json index b4bf8a274..cfe2f43b0 100644 --- a/public/intl/messages/ru-RU.json +++ b/public/intl/messages/ru-RU.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1972,7 +1972,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Вышла новая версия Umami " + "value": "Вышла новая версия Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/si-LK.json b/public/intl/messages/si-LK.json index 2dfa47f0f..5f1b4db1a 100644 --- a/public/intl/messages/si-LK.json +++ b/public/intl/messages/si-LK.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1988,7 +1988,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/sk-SK.json b/public/intl/messages/sk-SK.json index a1f1158b7..d7a28a198 100644 --- a/public/intl/messages/sk-SK.json +++ b/public/intl/messages/sk-SK.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/sl-SI.json b/public/intl/messages/sl-SI.json index 9f168f486..055adfa4e 100644 --- a/public/intl/messages/sl-SI.json +++ b/public/intl/messages/sl-SI.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1870,7 +1870,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Na voljo je nova verzija programa Umami " + "value": "Na voljo je nova verzija programa Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/sv-SE.json b/public/intl/messages/sv-SE.json index 684d44508..c64a024b4 100644 --- a/public/intl/messages/sv-SE.json +++ b/public/intl/messages/sv-SE.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -2000,7 +2000,7 @@ "message.new-version-available": [ { "type": 0, - "value": "En ny version av Umami " + "value": "En ny version av Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ta-IN.json b/public/intl/messages/ta-IN.json index 6d36a110a..7c66de792 100644 --- a/public/intl/messages/ta-IN.json +++ b/public/intl/messages/ta-IN.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/th-TH.json b/public/intl/messages/th-TH.json index cf3e5321b..386db1a7a 100644 --- a/public/intl/messages/th-TH.json +++ b/public/intl/messages/th-TH.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1992,7 +1992,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/tr-TR.json b/public/intl/messages/tr-TR.json index f7774fc79..ac9c9ec33 100644 --- a/public/intl/messages/tr-TR.json +++ b/public/intl/messages/tr-TR.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1956,7 +1956,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Yeni versiyon Umami " + "value": "Yeni versiyon Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/uk-UA.json b/public/intl/messages/uk-UA.json index d3a6dc79e..f84b07360 100644 --- a/public/intl/messages/uk-UA.json +++ b/public/intl/messages/uk-UA.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1972,7 +1972,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Вийшла нова версія Umami " + "value": "Вийшла нова версія Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/ur-PK.json b/public/intl/messages/ur-PK.json index 8eba7594d..3f7d1051b 100644 --- a/public/intl/messages/ur-PK.json +++ b/public/intl/messages/ur-PK.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1996,7 +1996,7 @@ "message.new-version-available": [ { "type": 0, - "value": "A new version of Umami " + "value": "A new version of Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/uz-UZ.json b/public/intl/messages/uz-UZ.json index 3697ff1be..8b8b4749a 100644 --- a/public/intl/messages/uz-UZ.json +++ b/public/intl/messages/uz-UZ.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1644,7 +1644,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Umami'ning yangi **" + "value": "Syncfuse'ning yangi **" }, { "type": 1, diff --git a/public/intl/messages/vi-VN.json b/public/intl/messages/vi-VN.json index dab46ca8c..62e2466d1 100644 --- a/public/intl/messages/vi-VN.json +++ b/public/intl/messages/vi-VN.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1652,7 +1652,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Có phiên bản mới của Umami " + "value": "Có phiên bản mới của Syncfuse " }, { "type": 1, diff --git a/public/intl/messages/zh-CN.json b/public/intl/messages/zh-CN.json index b3d2f3c00..7c7d26c31 100644 --- a/public/intl/messages/zh-CN.json +++ b/public/intl/messages/zh-CN.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1984,7 +1984,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Umami 新版本 " + "value": "Syncfuse 新版本 " }, { "type": 1, diff --git a/public/intl/messages/zh-TW.json b/public/intl/messages/zh-TW.json index db500a4bc..592ef775a 100644 --- a/public/intl/messages/zh-TW.json +++ b/public/intl/messages/zh-TW.json @@ -1,4 +1,4 @@ -{ +{ "label.access-code": [ { "type": 0, @@ -1964,7 +1964,7 @@ "message.new-version-available": [ { "type": 0, - "value": "Umami " + "value": "Syncfuse " }, { "type": 1, diff --git a/src/components/messages.ts b/src/components/messages.ts index 0438c06e6..4e28d294d 100644 --- a/src/components/messages.ts +++ b/src/components/messages.ts @@ -1,518 +1,516 @@ -import { defineMessages } from 'react-intl'; +import { defineMessages } from "react-intl"; export const labels = defineMessages({ - ok: { id: 'label.ok', defaultMessage: 'OK' }, - unknown: { id: 'label.unknown', defaultMessage: 'Unknown' }, - required: { id: 'label.required', defaultMessage: 'Required' }, - save: { id: 'label.save', defaultMessage: 'Save' }, - cancel: { id: 'label.cancel', defaultMessage: 'Cancel' }, - continue: { id: 'label.continue', defaultMessage: 'Continue' }, - delete: { id: 'label.delete', defaultMessage: 'Delete' }, - leave: { id: 'label.leave', defaultMessage: 'Leave' }, - users: { id: 'label.users', defaultMessage: 'Users' }, - createUser: { id: 'label.create-user', defaultMessage: 'Create user' }, - deleteUser: { id: 'label.delete-user', defaultMessage: 'Delete user' }, - username: { id: 'label.username', defaultMessage: 'Username' }, - password: { id: 'label.password', defaultMessage: 'Password' }, - role: { id: 'label.role', defaultMessage: 'Role' }, - user: { id: 'label.user', defaultMessage: 'User' }, - viewOnly: { id: 'label.view-only', defaultMessage: 'View only' }, - manage: { id: 'label.manage', defaultMessage: 'Manage' }, - admin: { id: 'label.admin', defaultMessage: 'Admin' }, - confirm: { id: 'label.confirm', defaultMessage: 'Confirm' }, - details: { id: 'label.details', defaultMessage: 'Details' }, - website: { id: 'label.website', defaultMessage: 'Website' }, - websites: { id: 'label.websites', defaultMessage: 'Websites' }, - myWebsites: { id: 'label.my-websites', defaultMessage: 'My websites' }, - teamWebsites: { id: 'label.team-websites', defaultMessage: 'Team websites' }, - created: { id: 'label.created', defaultMessage: 'Created' }, - createdBy: { id: 'label.created-by', defaultMessage: 'Created By' }, - edit: { id: 'label.edit', defaultMessage: 'Edit' }, - name: { id: 'label.name', defaultMessage: 'Name' }, - manager: { id: 'label.manager', defaultMessage: 'Manager' }, - member: { id: 'label.member', defaultMessage: 'Member' }, - members: { id: 'label.members', defaultMessage: 'Members' }, - accessCode: { id: 'label.access-code', defaultMessage: 'Access code' }, - teamId: { id: 'label.team-id', defaultMessage: 'Team ID' }, - team: { id: 'label.team', defaultMessage: 'Team' }, - teamName: { id: 'label.team-name', defaultMessage: 'Team name' }, - regenerate: { id: 'label.regenerate', defaultMessage: 'Regenerate' }, - remove: { id: 'label.remove', defaultMessage: 'Remove' }, - join: { id: 'label.join', defaultMessage: 'Join' }, - createTeam: { id: 'label.create-team', defaultMessage: 'Create team' }, - joinTeam: { id: 'label.join-team', defaultMessage: 'Join team' }, - settings: { id: 'label.settings', defaultMessage: 'Settings' }, - owner: { id: 'label.owner', defaultMessage: 'Owner' }, - teamOwner: { id: 'label.team-owner', defaultMessage: 'Team owner' }, - teamManager: { id: 'label.team-manager', defaultMessage: 'Team manager' }, - teamMember: { id: 'label.team-member', defaultMessage: 'Team member' }, - teamViewOnly: { id: 'label.team-view-only', defaultMessage: 'Team view only' }, - enableShareUrl: { id: 'label.enable-share-url', defaultMessage: 'Enable share URL' }, - data: { id: 'label.data', defaultMessage: 'Data' }, - trackingCode: { id: 'label.tracking-code', defaultMessage: 'Tracking code' }, - shareUrl: { id: 'label.share-url', defaultMessage: 'Share URL' }, - action: { id: 'label.action', defaultMessage: 'Action' }, - actions: { id: 'label.actions', defaultMessage: 'Actions' }, - domain: { id: 'label.domain', defaultMessage: 'Domain' }, - websiteId: { id: 'label.website-id', defaultMessage: 'Website ID' }, - resetWebsite: { id: 'label.reset-website', defaultMessage: 'Reset website' }, - deleteWebsite: { id: 'label.delete-website', defaultMessage: 'Delete website' }, - transferWebsite: { id: 'label.transfer-website', defaultMessage: 'Transfer website' }, - deleteReport: { id: 'label.delete-report', defaultMessage: 'Delete report' }, - reset: { id: 'label.reset', defaultMessage: 'Reset' }, - addWebsite: { id: 'label.add-website', defaultMessage: 'Add website' }, - addMember: { id: 'label.add-member', defaultMessage: 'Add member' }, - editMember: { id: 'label.edit-member', defaultMessage: 'Edit member' }, - removeMember: { id: 'label.remove-member', defaultMessage: 'Remove member' }, - addDescription: { id: 'label.add-description', defaultMessage: 'Add description' }, - changePassword: { id: 'label.change-password', defaultMessage: 'Change password' }, - currentPassword: { id: 'label.current-password', defaultMessage: 'Current password' }, - newPassword: { id: 'label.new-password', defaultMessage: 'New password' }, - confirmPassword: { id: 'label.confirm-password', defaultMessage: 'Confirm password' }, - timezone: { id: 'label.timezone', defaultMessage: 'Timezone' }, - defaultDateRange: { id: 'label.default-date-range', defaultMessage: 'Default date range' }, - language: { id: 'label.language', defaultMessage: 'Language' }, - theme: { id: 'label.theme', defaultMessage: 'Theme' }, - profile: { id: 'label.profile', defaultMessage: 'Profile' }, - profiles: { id: 'label.profiles', defaultMessage: 'Profiles' }, - dashboard: { id: 'label.dashboard', defaultMessage: 'Dashboard' }, - more: { id: 'label.more', defaultMessage: 'More' }, - realtime: { id: 'label.realtime', defaultMessage: 'Realtime' }, - queries: { id: 'label.queries', defaultMessage: 'Queries' }, - teams: { id: 'label.teams', defaultMessage: 'Teams' }, - teamSettings: { id: 'label.team-settings', defaultMessage: 'Team settings' }, - analytics: { id: 'label.analytics', defaultMessage: 'Analytics' }, - login: { id: 'label.login', defaultMessage: 'Login' }, - logout: { id: 'label.logout', defaultMessage: 'Logout' }, - singleDay: { id: 'label.single-day', defaultMessage: 'Single day' }, - dateRange: { id: 'label.date-range', defaultMessage: 'Date range' }, - viewDetails: { id: 'label.view-details', defaultMessage: 'View details' }, - deleteTeam: { id: 'label.delete-team', defaultMessage: 'Delete team' }, - leaveTeam: { id: 'label.leave-team', defaultMessage: 'Leave team' }, - refresh: { id: 'label.refresh', defaultMessage: 'Refresh' }, - page: { id: 'label.page', defaultMessage: 'Page' }, - pages: { id: 'label.pages', defaultMessage: 'Pages' }, - entry: { id: 'label.entry', defaultMessage: 'Entry' }, - exit: { id: 'label.exit', defaultMessage: 'Exit' }, - referrers: { id: 'label.referrers', defaultMessage: 'Referrers' }, - screen: { id: 'label.screen', defaultMessage: 'Screen' }, - screens: { id: 'label.screens', defaultMessage: 'Screens' }, - browsers: { id: 'label.browsers', defaultMessage: 'Browsers' }, - os: { id: 'label.os', defaultMessage: 'OS' }, - devices: { id: 'label.devices', defaultMessage: 'Devices' }, - countries: { id: 'label.countries', defaultMessage: 'Countries' }, - languages: { id: 'label.languages', defaultMessage: 'Languages' }, - tags: { id: 'label.tags', defaultMessage: 'Tags' }, - segments: { id: 'label.segments', defaultMessage: 'Segments' }, - cohorts: { id: 'label.cohorts', defaultMessage: 'Cohorts' }, - count: { id: 'label.count', defaultMessage: 'Count' }, - average: { id: 'label.average', defaultMessage: 'Average' }, - sum: { id: 'label.sum', defaultMessage: 'Sum' }, - event: { id: 'label.event', defaultMessage: 'Event' }, - events: { id: 'label.events', defaultMessage: 'Events' }, - eventName: { id: 'label.event-name', defaultMessage: 'Event name' }, - query: { id: 'label.query', defaultMessage: 'Query' }, - queryParameters: { id: 'label.query-parameters', defaultMessage: 'Query parameters' }, - back: { id: 'label.back', defaultMessage: 'Back' }, - visitors: { id: 'label.visitors', defaultMessage: 'Visitors' }, - visits: { id: 'label.visits', defaultMessage: 'Visits' }, - filterCombined: { id: 'label.filter-combined', defaultMessage: 'Combined' }, - filterRaw: { id: 'label.filter-raw', defaultMessage: 'Raw' }, - views: { id: 'label.views', defaultMessage: 'Views' }, - none: { id: 'label.none', defaultMessage: 'None' }, - clearAll: { id: 'label.clear-all', defaultMessage: 'Clear all' }, - property: { id: 'label.property', defaultMessage: 'Property' }, - today: { id: 'label.today', defaultMessage: 'Today' }, - lastHours: { id: 'label.last-hours', defaultMessage: 'Last {x} hours' }, - yesterday: { id: 'label.yesterday', defaultMessage: 'Yesterday' }, - thisWeek: { id: 'label.this-week', defaultMessage: 'This week' }, - lastDays: { id: 'label.last-days', defaultMessage: 'Last {x} days' }, - lastMonths: { id: 'label.last-months', defaultMessage: 'Last {x} months' }, - thisMonth: { id: 'label.this-month', defaultMessage: 'This month' }, - thisYear: { id: 'label.this-year', defaultMessage: 'This year' }, - allTime: { id: 'label.all-time', defaultMessage: 'All time' }, - customRange: { id: 'label.custom-range', defaultMessage: 'Custom range' }, - selectWebsite: { id: 'label.select-website', defaultMessage: 'Select website' }, - selectRole: { id: 'label.select-role', defaultMessage: 'Select role' }, - selectDate: { id: 'label.select-date', defaultMessage: 'Select date' }, - selectFilter: { id: 'label.select-filter', defaultMessage: 'Select filter' }, - all: { id: 'label.all', defaultMessage: 'All' }, - session: { id: 'label.session', defaultMessage: 'Session' }, - sessions: { id: 'label.sessions', defaultMessage: 'Sessions' }, - distinctId: { id: 'label.distinct-id', defaultMessage: 'Distinct ID' }, - pageNotFound: { id: 'message.page-not-found', defaultMessage: 'Page not found' }, - activity: { id: 'label.activity', defaultMessage: 'Activity' }, - dismiss: { id: 'label.dismiss', defaultMessage: 'Dismiss' }, - poweredBy: { id: 'label.powered-by', defaultMessage: 'Powered by {name}' }, - pageViews: { id: 'label.page-views', defaultMessage: 'Page views' }, - uniqueVisitors: { id: 'label.unique-visitors', defaultMessage: 'Unique visitors' }, - bounceRate: { id: 'label.bounce-rate', defaultMessage: 'Bounce rate' }, - viewsPerVisit: { id: 'label.views-per-visit', defaultMessage: 'Views per visit' }, - visitDuration: { id: 'label.visit-duration', defaultMessage: 'Visit duration' }, - desktop: { id: 'label.desktop', defaultMessage: 'Desktop' }, - laptop: { id: 'label.laptop', defaultMessage: 'Laptop' }, - tablet: { id: 'label.tablet', defaultMessage: 'Tablet' }, - mobile: { id: 'label.mobile', defaultMessage: 'Mobile' }, - toggleCharts: { id: 'label.toggle-charts', defaultMessage: 'Toggle charts' }, - editDashboard: { id: 'label.edit-dashboard', defaultMessage: 'Edit dashboard' }, - title: { id: 'label.title', defaultMessage: 'Title' }, - view: { id: 'label.view', defaultMessage: 'View' }, - cities: { id: 'label.cities', defaultMessage: 'Cities' }, - 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' }, - funnels: { id: 'label.funnels', defaultMessage: 'Funnels' }, + ok: { id: "label.ok", defaultMessage: "OK" }, + unknown: { id: "label.unknown", defaultMessage: "Unknown" }, + required: { id: "label.required", defaultMessage: "Required" }, + save: { id: "label.save", defaultMessage: "Save" }, + cancel: { id: "label.cancel", defaultMessage: "Cancel" }, + continue: { id: "label.continue", defaultMessage: "Continue" }, + delete: { id: "label.delete", defaultMessage: "Delete" }, + leave: { id: "label.leave", defaultMessage: "Leave" }, + users: { id: "label.users", defaultMessage: "Users" }, + createUser: { id: "label.create-user", defaultMessage: "Create user" }, + deleteUser: { id: "label.delete-user", defaultMessage: "Delete user" }, + username: { id: "label.username", defaultMessage: "Username" }, + password: { id: "label.password", defaultMessage: "Password" }, + role: { id: "label.role", defaultMessage: "Role" }, + user: { id: "label.user", defaultMessage: "User" }, + viewOnly: { id: "label.view-only", defaultMessage: "View only" }, + manage: { id: "label.manage", defaultMessage: "Manage" }, + admin: { id: "label.admin", defaultMessage: "Admin" }, + confirm: { id: "label.confirm", defaultMessage: "Confirm" }, + details: { id: "label.details", defaultMessage: "Details" }, + website: { id: "label.website", defaultMessage: "Website" }, + websites: { id: "label.websites", defaultMessage: "Websites" }, + myWebsites: { id: "label.my-websites", defaultMessage: "My websites" }, + teamWebsites: { id: "label.team-websites", defaultMessage: "Team websites" }, + created: { id: "label.created", defaultMessage: "Created" }, + createdBy: { id: "label.created-by", defaultMessage: "Created By" }, + edit: { id: "label.edit", defaultMessage: "Edit" }, + name: { id: "label.name", defaultMessage: "Name" }, + manager: { id: "label.manager", defaultMessage: "Manager" }, + member: { id: "label.member", defaultMessage: "Member" }, + members: { id: "label.members", defaultMessage: "Members" }, + accessCode: { id: "label.access-code", defaultMessage: "Access code" }, + teamId: { id: "label.team-id", defaultMessage: "Team ID" }, + team: { id: "label.team", defaultMessage: "Team" }, + teamName: { id: "label.team-name", defaultMessage: "Team name" }, + regenerate: { id: "label.regenerate", defaultMessage: "Regenerate" }, + remove: { id: "label.remove", defaultMessage: "Remove" }, + join: { id: "label.join", defaultMessage: "Join" }, + createTeam: { id: "label.create-team", defaultMessage: "Create team" }, + joinTeam: { id: "label.join-team", defaultMessage: "Join team" }, + settings: { id: "label.settings", defaultMessage: "Settings" }, + owner: { id: "label.owner", defaultMessage: "Owner" }, + teamOwner: { id: "label.team-owner", defaultMessage: "Team owner" }, + teamManager: { id: "label.team-manager", defaultMessage: "Team manager" }, + teamMember: { id: "label.team-member", defaultMessage: "Team member" }, + teamViewOnly: { id: "label.team-view-only", defaultMessage: "Team view only" }, + enableShareUrl: { id: "label.enable-share-url", defaultMessage: "Enable share URL" }, + data: { id: "label.data", defaultMessage: "Data" }, + trackingCode: { id: "label.tracking-code", defaultMessage: "Tracking code" }, + shareUrl: { id: "label.share-url", defaultMessage: "Share URL" }, + action: { id: "label.action", defaultMessage: "Action" }, + actions: { id: "label.actions", defaultMessage: "Actions" }, + domain: { id: "label.domain", defaultMessage: "Domain" }, + websiteId: { id: "label.website-id", defaultMessage: "Website ID" }, + resetWebsite: { id: "label.reset-website", defaultMessage: "Reset website" }, + deleteWebsite: { id: "label.delete-website", defaultMessage: "Delete website" }, + transferWebsite: { id: "label.transfer-website", defaultMessage: "Transfer website" }, + deleteReport: { id: "label.delete-report", defaultMessage: "Delete report" }, + reset: { id: "label.reset", defaultMessage: "Reset" }, + addWebsite: { id: "label.add-website", defaultMessage: "Add website" }, + addMember: { id: "label.add-member", defaultMessage: "Add member" }, + editMember: { id: "label.edit-member", defaultMessage: "Edit member" }, + removeMember: { id: "label.remove-member", defaultMessage: "Remove member" }, + addDescription: { id: "label.add-description", defaultMessage: "Add description" }, + changePassword: { id: "label.change-password", defaultMessage: "Change password" }, + currentPassword: { id: "label.current-password", defaultMessage: "Current password" }, + newPassword: { id: "label.new-password", defaultMessage: "New password" }, + confirmPassword: { id: "label.confirm-password", defaultMessage: "Confirm password" }, + timezone: { id: "label.timezone", defaultMessage: "Timezone" }, + defaultDateRange: { id: "label.default-date-range", defaultMessage: "Default date range" }, + language: { id: "label.language", defaultMessage: "Language" }, + theme: { id: "label.theme", defaultMessage: "Theme" }, + profile: { id: "label.profile", defaultMessage: "Profile" }, + profiles: { id: "label.profiles", defaultMessage: "Profiles" }, + dashboard: { id: "label.dashboard", defaultMessage: "Dashboard" }, + more: { id: "label.more", defaultMessage: "More" }, + realtime: { id: "label.realtime", defaultMessage: "Realtime" }, + queries: { id: "label.queries", defaultMessage: "Queries" }, + teams: { id: "label.teams", defaultMessage: "Teams" }, + teamSettings: { id: "label.team-settings", defaultMessage: "Team settings" }, + analytics: { id: "label.analytics", defaultMessage: "Analytics" }, + login: { id: "label.login", defaultMessage: "Login" }, + logout: { id: "label.logout", defaultMessage: "Logout" }, + singleDay: { id: "label.single-day", defaultMessage: "Single day" }, + dateRange: { id: "label.date-range", defaultMessage: "Date range" }, + viewDetails: { id: "label.view-details", defaultMessage: "View details" }, + deleteTeam: { id: "label.delete-team", defaultMessage: "Delete team" }, + leaveTeam: { id: "label.leave-team", defaultMessage: "Leave team" }, + refresh: { id: "label.refresh", defaultMessage: "Refresh" }, + page: { id: "label.page", defaultMessage: "Page" }, + pages: { id: "label.pages", defaultMessage: "Pages" }, + entry: { id: "label.entry", defaultMessage: "Entry" }, + exit: { id: "label.exit", defaultMessage: "Exit" }, + referrers: { id: "label.referrers", defaultMessage: "Referrers" }, + screen: { id: "label.screen", defaultMessage: "Screen" }, + screens: { id: "label.screens", defaultMessage: "Screens" }, + browsers: { id: "label.browsers", defaultMessage: "Browsers" }, + os: { id: "label.os", defaultMessage: "OS" }, + devices: { id: "label.devices", defaultMessage: "Devices" }, + countries: { id: "label.countries", defaultMessage: "Countries" }, + languages: { id: "label.languages", defaultMessage: "Languages" }, + tags: { id: "label.tags", defaultMessage: "Tags" }, + segments: { id: "label.segments", defaultMessage: "Segments" }, + cohorts: { id: "label.cohorts", defaultMessage: "Cohorts" }, + count: { id: "label.count", defaultMessage: "Count" }, + average: { id: "label.average", defaultMessage: "Average" }, + sum: { id: "label.sum", defaultMessage: "Sum" }, + event: { id: "label.event", defaultMessage: "Event" }, + events: { id: "label.events", defaultMessage: "Events" }, + eventName: { id: "label.event-name", defaultMessage: "Event name" }, + query: { id: "label.query", defaultMessage: "Query" }, + queryParameters: { id: "label.query-parameters", defaultMessage: "Query parameters" }, + back: { id: "label.back", defaultMessage: "Back" }, + visitors: { id: "label.visitors", defaultMessage: "Visitors" }, + visits: { id: "label.visits", defaultMessage: "Visits" }, + filterCombined: { id: "label.filter-combined", defaultMessage: "Combined" }, + filterRaw: { id: "label.filter-raw", defaultMessage: "Raw" }, + views: { id: "label.views", defaultMessage: "Views" }, + none: { id: "label.none", defaultMessage: "None" }, + clearAll: { id: "label.clear-all", defaultMessage: "Clear all" }, + property: { id: "label.property", defaultMessage: "Property" }, + today: { id: "label.today", defaultMessage: "Today" }, + lastHours: { id: "label.last-hours", defaultMessage: "Last {x} hours" }, + yesterday: { id: "label.yesterday", defaultMessage: "Yesterday" }, + thisWeek: { id: "label.this-week", defaultMessage: "This week" }, + lastDays: { id: "label.last-days", defaultMessage: "Last {x} days" }, + lastMonths: { id: "label.last-months", defaultMessage: "Last {x} months" }, + thisMonth: { id: "label.this-month", defaultMessage: "This month" }, + thisYear: { id: "label.this-year", defaultMessage: "This year" }, + allTime: { id: "label.all-time", defaultMessage: "All time" }, + customRange: { id: "label.custom-range", defaultMessage: "Custom range" }, + selectWebsite: { id: "label.select-website", defaultMessage: "Select website" }, + selectRole: { id: "label.select-role", defaultMessage: "Select role" }, + selectDate: { id: "label.select-date", defaultMessage: "Select date" }, + selectFilter: { id: "label.select-filter", defaultMessage: "Select filter" }, + all: { id: "label.all", defaultMessage: "All" }, + session: { id: "label.session", defaultMessage: "Session" }, + sessions: { id: "label.sessions", defaultMessage: "Sessions" }, + distinctId: { id: "label.distinct-id", defaultMessage: "Distinct ID" }, + pageNotFound: { id: "message.page-not-found", defaultMessage: "Page not found" }, + activity: { id: "label.activity", defaultMessage: "Activity" }, + dismiss: { id: "label.dismiss", defaultMessage: "Dismiss" }, + poweredBy: { id: "label.powered-by", defaultMessage: "Powered by {name}" }, + pageViews: { id: "label.page-views", defaultMessage: "Page views" }, + uniqueVisitors: { id: "label.unique-visitors", defaultMessage: "Unique visitors" }, + bounceRate: { id: "label.bounce-rate", defaultMessage: "Bounce rate" }, + viewsPerVisit: { id: "label.views-per-visit", defaultMessage: "Views per visit" }, + visitDuration: { id: "label.visit-duration", defaultMessage: "Visit duration" }, + desktop: { id: "label.desktop", defaultMessage: "Desktop" }, + laptop: { id: "label.laptop", defaultMessage: "Laptop" }, + tablet: { id: "label.tablet", defaultMessage: "Tablet" }, + mobile: { id: "label.mobile", defaultMessage: "Mobile" }, + toggleCharts: { id: "label.toggle-charts", defaultMessage: "Toggle charts" }, + editDashboard: { id: "label.edit-dashboard", defaultMessage: "Edit dashboard" }, + title: { id: "label.title", defaultMessage: "Title" }, + view: { id: "label.view", defaultMessage: "View" }, + cities: { id: "label.cities", defaultMessage: "Cities" }, + 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" }, + funnels: { id: "label.funnels", defaultMessage: "Funnels" }, funnelDescription: { - id: 'label.funnel-description', - defaultMessage: 'Understand the conversion and drop-off rate of users.', + id: "label.funnel-description", + defaultMessage: "Understand the conversion and drop-off rate of users.", }, - revenue: { id: 'label.revenue', defaultMessage: 'Revenue' }, + revenue: { id: "label.revenue", defaultMessage: "Revenue" }, revenueDescription: { - id: 'label.revenue-description', - defaultMessage: 'Look into your revenue data and how users are spending.', + id: "label.revenue-description", + defaultMessage: "Look into your revenue data and how users are spending.", }, - attribution: { id: 'label.attribution', defaultMessage: 'Attribution' }, + attribution: { id: "label.attribution", defaultMessage: "Attribution" }, attributionDescription: { - id: 'label.attribution-description', - defaultMessage: 'See how users engage with your marketing and what drives conversions.', + id: "label.attribution-description", + defaultMessage: "See how users engage with your marketing and what drives conversions.", }, - currency: { id: 'label.currency', defaultMessage: 'Currency' }, - model: { id: 'label.model', defaultMessage: 'Model' }, - path: { id: 'label.path', defaultMessage: 'Path' }, - paths: { id: 'label.paths', defaultMessage: 'Paths' }, - add: { id: 'label.add', defaultMessage: 'Add' }, - update: { id: 'label.update', defaultMessage: 'Update' }, - window: { id: 'label.window', defaultMessage: 'Window' }, - runQuery: { id: 'label.run-query', defaultMessage: 'Run query' }, - field: { id: 'label.field', defaultMessage: 'Field' }, - fields: { id: 'label.fields', defaultMessage: 'Fields' }, - createReport: { id: 'label.create-report', defaultMessage: 'Create report' }, - description: { id: 'label.description', defaultMessage: 'Description' }, - untitled: { id: 'label.untitled', defaultMessage: 'Untitled' }, - type: { id: 'label.type', defaultMessage: 'Type' }, - filter: { id: 'label.filter', defaultMessage: 'Filter' }, - filters: { id: 'label.filters', defaultMessage: 'Filters' }, - breakdown: { id: 'label.breakdown', defaultMessage: 'Breakdown' }, - true: { id: 'label.true', defaultMessage: 'True' }, - false: { id: 'label.false', defaultMessage: 'False' }, - is: { id: 'label.is', defaultMessage: 'Is' }, - isNot: { id: 'label.is-not', defaultMessage: 'Is not' }, - isSet: { id: 'label.is-set', defaultMessage: 'Is set' }, - isNotSet: { id: 'label.is-not-set', defaultMessage: 'Is not set' }, - greaterThan: { id: 'label.greater-than', defaultMessage: 'Greater than' }, - lessThan: { id: 'label.less-than', defaultMessage: 'Less than' }, - greaterThanEquals: { id: 'label.greater-than-equals', defaultMessage: 'Greater than or equals' }, - lessThanEquals: { id: 'label.less-than-equals', defaultMessage: 'Less than or equals' }, - contains: { id: 'label.contains', defaultMessage: 'Contains' }, - doesNotContain: { id: 'label.does-not-contain', defaultMessage: 'Does not contain' }, - includes: { id: 'label.includes', defaultMessage: 'Includes' }, - doesNotInclude: { id: 'label.does-not-include', defaultMessage: 'Does not include' }, - before: { id: 'label.before', defaultMessage: 'Before' }, - after: { id: 'label.after', defaultMessage: 'After' }, - isTrue: { id: 'label.is-true', defaultMessage: 'Is true' }, - isFalse: { id: 'label.is-false', defaultMessage: 'Is false' }, - exists: { id: 'label.exists', defaultMessage: 'Exists' }, - doesNotExist: { id: 'label.doest-not-exist', defaultMessage: 'Does not exist' }, - total: { id: 'label.total', defaultMessage: 'Total' }, - min: { id: 'label.min', defaultMessage: 'Min' }, - max: { id: 'label.max', defaultMessage: 'Max' }, - unique: { id: 'label.unique', defaultMessage: 'Unique' }, - value: { id: 'label.value', defaultMessage: 'Value' }, - overview: { id: 'label.overview', defaultMessage: 'Overview' }, - totalRecords: { id: 'label.total-records', defaultMessage: 'Total records' }, - insight: { id: 'label.insight', defaultMessage: 'Insight' }, - insights: { id: 'label.insights', defaultMessage: 'Insights' }, + currency: { id: "label.currency", defaultMessage: "Currency" }, + model: { id: "label.model", defaultMessage: "Model" }, + path: { id: "label.path", defaultMessage: "Path" }, + paths: { id: "label.paths", defaultMessage: "Paths" }, + add: { id: "label.add", defaultMessage: "Add" }, + update: { id: "label.update", defaultMessage: "Update" }, + window: { id: "label.window", defaultMessage: "Window" }, + runQuery: { id: "label.run-query", defaultMessage: "Run query" }, + field: { id: "label.field", defaultMessage: "Field" }, + fields: { id: "label.fields", defaultMessage: "Fields" }, + createReport: { id: "label.create-report", defaultMessage: "Create report" }, + description: { id: "label.description", defaultMessage: "Description" }, + untitled: { id: "label.untitled", defaultMessage: "Untitled" }, + type: { id: "label.type", defaultMessage: "Type" }, + filter: { id: "label.filter", defaultMessage: "Filter" }, + filters: { id: "label.filters", defaultMessage: "Filters" }, + breakdown: { id: "label.breakdown", defaultMessage: "Breakdown" }, + true: { id: "label.true", defaultMessage: "True" }, + false: { id: "label.false", defaultMessage: "False" }, + is: { id: "label.is", defaultMessage: "Is" }, + isNot: { id: "label.is-not", defaultMessage: "Is not" }, + isSet: { id: "label.is-set", defaultMessage: "Is set" }, + isNotSet: { id: "label.is-not-set", defaultMessage: "Is not set" }, + greaterThan: { id: "label.greater-than", defaultMessage: "Greater than" }, + lessThan: { id: "label.less-than", defaultMessage: "Less than" }, + greaterThanEquals: { id: "label.greater-than-equals", defaultMessage: "Greater than or equals" }, + lessThanEquals: { id: "label.less-than-equals", defaultMessage: "Less than or equals" }, + contains: { id: "label.contains", defaultMessage: "Contains" }, + doesNotContain: { id: "label.does-not-contain", defaultMessage: "Does not contain" }, + includes: { id: "label.includes", defaultMessage: "Includes" }, + doesNotInclude: { id: "label.does-not-include", defaultMessage: "Does not include" }, + before: { id: "label.before", defaultMessage: "Before" }, + after: { id: "label.after", defaultMessage: "After" }, + isTrue: { id: "label.is-true", defaultMessage: "Is true" }, + isFalse: { id: "label.is-false", defaultMessage: "Is false" }, + exists: { id: "label.exists", defaultMessage: "Exists" }, + doesNotExist: { id: "label.doest-not-exist", defaultMessage: "Does not exist" }, + total: { id: "label.total", defaultMessage: "Total" }, + min: { id: "label.min", defaultMessage: "Min" }, + max: { id: "label.max", defaultMessage: "Max" }, + unique: { id: "label.unique", defaultMessage: "Unique" }, + value: { id: "label.value", defaultMessage: "Value" }, + overview: { id: "label.overview", defaultMessage: "Overview" }, + totalRecords: { id: "label.total-records", defaultMessage: "Total records" }, + insight: { id: "label.insight", defaultMessage: "Insight" }, + insights: { id: "label.insights", defaultMessage: "Insights" }, insightsDescription: { - id: 'label.insights-description', - defaultMessage: 'Dive deeper into your data by using segments and filters.', + id: "label.insights-description", + defaultMessage: "Dive deeper into your data by using segments and filters.", }, - retention: { id: 'label.retention', defaultMessage: 'Retention' }, + retention: { id: "label.retention", defaultMessage: "Retention" }, retentionDescription: { - id: 'label.retention-description', - defaultMessage: 'Measure your website stickiness by tracking how often users return.', + id: "label.retention-description", + defaultMessage: "Measure your website stickiness by tracking how often users return.", }, - dropoff: { id: 'label.dropoff', defaultMessage: 'Dropoff' }, - referrer: { id: 'label.referrer', defaultMessage: 'Referrer' }, - hostname: { id: 'label.hostname', defaultMessage: 'Hostname' }, - country: { id: 'label.country', defaultMessage: 'Country' }, - region: { id: 'label.region', defaultMessage: 'Region' }, - city: { id: 'label.city', defaultMessage: 'City' }, - 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' }, - segment: { id: 'label.segment', defaultMessage: 'Segment' }, - cohort: { id: 'label.cohort', defaultMessage: 'Cohort' }, - day: { id: 'label.day', defaultMessage: 'Day' }, - date: { id: 'label.date', defaultMessage: 'Date' }, - pageOf: { id: 'label.page-of', defaultMessage: 'Page {current} of {total}' }, - create: { id: 'label.create', defaultMessage: 'Create' }, - search: { id: 'label.search', defaultMessage: 'Search' }, + dropoff: { id: "label.dropoff", defaultMessage: "Dropoff" }, + referrer: { id: "label.referrer", defaultMessage: "Referrer" }, + hostname: { id: "label.hostname", defaultMessage: "Hostname" }, + country: { id: "label.country", defaultMessage: "Country" }, + region: { id: "label.region", defaultMessage: "Region" }, + city: { id: "label.city", defaultMessage: "City" }, + 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" }, + segment: { id: "label.segment", defaultMessage: "Segment" }, + cohort: { id: "label.cohort", defaultMessage: "Cohort" }, + day: { id: "label.day", defaultMessage: "Day" }, + date: { id: "label.date", defaultMessage: "Date" }, + pageOf: { id: "label.page-of", defaultMessage: "Page {current} of {total}" }, + create: { id: "label.create", defaultMessage: "Create" }, + search: { id: "label.search", defaultMessage: "Search" }, numberOfRecords: { - id: 'label.number-of-records', - defaultMessage: '{x} {x, plural, one {record} other {records}}', + id: "label.number-of-records", + defaultMessage: "{x} {x, plural, one {record} other {records}}", }, - select: { id: 'label.select', defaultMessage: 'Select' }, - myAccount: { id: 'label.my-account', defaultMessage: 'My account' }, - transfer: { id: 'label.transfer', defaultMessage: 'Transfer' }, - transactions: { id: 'label.transactions', defaultMessage: 'Transactions' }, - uniqueCustomers: { id: 'label.uniqueCustomers', defaultMessage: 'Unique Customers' }, + select: { id: "label.select", defaultMessage: "Select" }, + myAccount: { id: "label.my-account", defaultMessage: "My account" }, + transfer: { id: "label.transfer", defaultMessage: "Transfer" }, + transactions: { id: "label.transactions", defaultMessage: "Transactions" }, + uniqueCustomers: { id: "label.uniqueCustomers", defaultMessage: "Unique Customers" }, viewedPage: { - id: 'message.viewed-page', - defaultMessage: 'Viewed page', + id: "message.viewed-page", + defaultMessage: "Viewed page", }, collectedData: { - id: 'message.collected-data', - defaultMessage: 'Collected data', + id: "message.collected-data", + defaultMessage: "Collected data", }, triggeredEvent: { - id: 'message.triggered-event', - defaultMessage: 'Triggered event', + id: "message.triggered-event", + defaultMessage: "Triggered event", }, - utm: { id: 'label.utm', defaultMessage: 'UTM' }, + utm: { id: "label.utm", defaultMessage: "UTM" }, utmDescription: { - id: 'label.utm-description', - defaultMessage: 'Track your campaigns through UTM parameters.', + id: "label.utm-description", + defaultMessage: "Track your campaigns through UTM parameters.", }, - conversionStep: { id: 'label.conversion-step', defaultMessage: 'Conversion step' }, - conversionRate: { id: 'label.conversion-rate', defaultMessage: 'Conversion rate' }, - steps: { id: 'label.steps', defaultMessage: 'Steps' }, - startStep: { id: 'label.start-step', defaultMessage: 'Start Step' }, - endStep: { id: 'label.end-step', defaultMessage: 'End Step' }, - addStep: { id: 'label.add-step', defaultMessage: 'Add step' }, - goal: { id: 'label.goal', defaultMessage: 'Goal' }, - goals: { id: 'label.goals', defaultMessage: 'Goals' }, + conversionStep: { id: "label.conversion-step", defaultMessage: "Conversion step" }, + conversionRate: { id: "label.conversion-rate", defaultMessage: "Conversion rate" }, + steps: { id: "label.steps", defaultMessage: "Steps" }, + startStep: { id: "label.start-step", defaultMessage: "Start Step" }, + endStep: { id: "label.end-step", defaultMessage: "End Step" }, + addStep: { id: "label.add-step", defaultMessage: "Add step" }, + goal: { id: "label.goal", defaultMessage: "Goal" }, + goals: { id: "label.goals", defaultMessage: "Goals" }, goalsDescription: { - id: 'label.goals-description', - defaultMessage: 'Track your goals for pageviews and events.', + id: "label.goals-description", + defaultMessage: "Track your goals for pageviews and events.", }, - journey: { id: 'label.journey', defaultMessage: 'Journey' }, - journeys: { id: 'label.journeys', defaultMessage: 'Journeys' }, + journey: { id: "label.journey", defaultMessage: "Journey" }, + journeys: { id: "label.journeys", defaultMessage: "Journeys" }, journeyDescription: { - id: 'label.journey-description', - defaultMessage: 'Understand how users navigate through your website.', + id: "label.journey-description", + defaultMessage: "Understand how users navigate through your website.", }, - compareDates: { id: 'label.compare-dates', defaultMessage: 'Compare dates' }, - compare: { id: 'label.compare', defaultMessage: 'Compare' }, - current: { id: 'label.current', defaultMessage: 'Current' }, - previous: { id: 'label.previous', defaultMessage: 'Previous' }, - previousPeriod: { id: 'label.previous-period', defaultMessage: 'Previous period' }, - previousYear: { id: 'label.previous-year', defaultMessage: 'Previous year' }, - lastSeen: { id: 'label.last-seen', defaultMessage: 'Last seen' }, - firstSeen: { id: 'label.first-seen', defaultMessage: 'First seen' }, - properties: { id: 'label.properties', defaultMessage: 'Properties' }, - channel: { id: 'label.channel', defaultMessage: 'Channel' }, - channels: { id: 'label.channels', defaultMessage: 'Channels' }, - sources: { id: 'label.sources', defaultMessage: 'Sources' }, - medium: { id: 'label.medium', defaultMessage: 'Medium' }, - campaigns: { id: 'label.campaigns', defaultMessage: 'Campaigns' }, - content: { id: 'label.content', defaultMessage: 'Content' }, - terms: { id: 'label.terms', defaultMessage: 'Terms' }, - direct: { id: 'label.direct', defaultMessage: 'Direct' }, - referral: { id: 'label.referral', defaultMessage: 'Referral' }, - affiliate: { id: 'label.affiliate', defaultMessage: 'Affiliate' }, - email: { id: 'label.email', defaultMessage: 'Email' }, - sms: { id: 'label.sms', defaultMessage: 'SMS' }, - organicSearch: { id: 'label.organic-search', defaultMessage: 'Organic search' }, - organicSocial: { id: 'label.organic-social', defaultMessage: 'Organic social' }, - organicShopping: { id: 'label.organic-shopping', defaultMessage: 'Organic shopping' }, - organicVideo: { id: 'label.organic-video', defaultMessage: 'Organic video' }, - paidAds: { id: 'label.paid-ads', defaultMessage: 'Paid ads' }, - paidSearch: { id: 'label.paid-search', defaultMessage: 'Paid search' }, - paidSocial: { id: 'label.paid-social', defaultMessage: 'Paid social' }, - paidShopping: { id: 'label.paid-shopping', defaultMessage: 'Paid shopping' }, - paidVideo: { id: 'label.paid-video', defaultMessage: 'Paid video' }, - grouped: { id: 'label.grouped', defaultMessage: 'Grouped' }, - other: { id: 'label.other', defaultMessage: 'Other' }, - boards: { id: 'label.boards', defaultMessage: 'Boards' }, - apply: { id: 'label.apply', defaultMessage: 'Apply' }, - link: { id: 'label.link', defaultMessage: 'Link' }, - links: { id: 'label.links', defaultMessage: 'Links' }, - pixel: { id: 'label.pixel', defaultMessage: 'Pixel' }, - pixels: { id: 'label.pixels', defaultMessage: 'Pixels' }, - addBoard: { id: 'label.add-board', defaultMessage: 'Add board' }, - addLink: { id: 'label.add-link', defaultMessage: 'Add link' }, - addPixel: { id: 'label.add-pixel', defaultMessage: 'Add pixel' }, - maximize: { id: 'label.maximize', defaultMessage: 'Maximize' }, - remaining: { id: 'label.remaining', defaultMessage: 'Remaining' }, - conversion: { id: 'label.conversion', defaultMessage: 'Conversion' }, - firstClick: { id: 'label.first-click', defaultMessage: 'First click' }, - lastClick: { id: 'label.last-click', defaultMessage: 'Last click' }, - online: { id: 'label.online', defaultMessage: 'Online' }, - preferences: { id: 'label.preferences', defaultMessage: 'Preferences' }, - location: { id: 'label.location', defaultMessage: 'Location' }, - chart: { id: 'label.chart', defaultMessage: 'Chart' }, - table: { id: 'label.table', defaultMessage: 'Table' }, - download: { id: 'label.download', defaultMessage: 'Download' }, - traffic: { id: 'label.traffic', defaultMessage: 'Traffic' }, - behavior: { id: 'label.behavior', defaultMessage: 'Behavior' }, - growth: { id: 'label.growth', defaultMessage: 'Growth' }, - account: { id: 'label.account', defaultMessage: 'Account' }, - application: { id: 'label.application', defaultMessage: 'Application' }, - saveSegment: { id: 'label.save-segment', defaultMessage: 'Save as segment' }, - saveCohort: { id: 'label.save-cohort', defaultMessage: 'Save as cohort' }, - analysis: { id: 'label.analysis', defaultMessage: 'Analysis' }, - destinationUrl: { id: 'label.destination-url', defaultMessage: 'Destination URL' }, - audience: { id: 'label.audience', defaultMessage: 'Audience' }, - invalidUrl: { id: 'label.invalid-url', defaultMessage: 'Invalid URL' }, - environment: { id: 'label.environment', defaultMessage: 'Environment' }, - criteria: { id: 'label.criteria', defaultMessage: 'Criteria' }, - share: { id: 'label.share', defaultMessage: 'Share' }, - support: { id: 'label.support', defaultMessage: 'Support' }, - documentation: { id: 'label.documentation', defaultMessage: 'Documentation' }, - switchAccount: { id: 'label.switch-account', defaultMessage: 'Switch account' }, + compareDates: { id: "label.compare-dates", defaultMessage: "Compare dates" }, + compare: { id: "label.compare", defaultMessage: "Compare" }, + current: { id: "label.current", defaultMessage: "Current" }, + previous: { id: "label.previous", defaultMessage: "Previous" }, + previousPeriod: { id: "label.previous-period", defaultMessage: "Previous period" }, + previousYear: { id: "label.previous-year", defaultMessage: "Previous year" }, + lastSeen: { id: "label.last-seen", defaultMessage: "Last seen" }, + firstSeen: { id: "label.first-seen", defaultMessage: "First seen" }, + properties: { id: "label.properties", defaultMessage: "Properties" }, + channel: { id: "label.channel", defaultMessage: "Channel" }, + channels: { id: "label.channels", defaultMessage: "Channels" }, + sources: { id: "label.sources", defaultMessage: "Sources" }, + medium: { id: "label.medium", defaultMessage: "Medium" }, + campaigns: { id: "label.campaigns", defaultMessage: "Campaigns" }, + content: { id: "label.content", defaultMessage: "Content" }, + terms: { id: "label.terms", defaultMessage: "Terms" }, + direct: { id: "label.direct", defaultMessage: "Direct" }, + referral: { id: "label.referral", defaultMessage: "Referral" }, + affiliate: { id: "label.affiliate", defaultMessage: "Affiliate" }, + email: { id: "label.email", defaultMessage: "Email" }, + sms: { id: "label.sms", defaultMessage: "SMS" }, + organicSearch: { id: "label.organic-search", defaultMessage: "Organic search" }, + organicSocial: { id: "label.organic-social", defaultMessage: "Organic social" }, + organicShopping: { id: "label.organic-shopping", defaultMessage: "Organic shopping" }, + organicVideo: { id: "label.organic-video", defaultMessage: "Organic video" }, + paidAds: { id: "label.paid-ads", defaultMessage: "Paid ads" }, + paidSearch: { id: "label.paid-search", defaultMessage: "Paid search" }, + paidSocial: { id: "label.paid-social", defaultMessage: "Paid social" }, + paidShopping: { id: "label.paid-shopping", defaultMessage: "Paid shopping" }, + paidVideo: { id: "label.paid-video", defaultMessage: "Paid video" }, + grouped: { id: "label.grouped", defaultMessage: "Grouped" }, + other: { id: "label.other", defaultMessage: "Other" }, + boards: { id: "label.boards", defaultMessage: "Boards" }, + apply: { id: "label.apply", defaultMessage: "Apply" }, + link: { id: "label.link", defaultMessage: "Link" }, + links: { id: "label.links", defaultMessage: "Links" }, + pixel: { id: "label.pixel", defaultMessage: "Pixel" }, + pixels: { id: "label.pixels", defaultMessage: "Pixels" }, + addBoard: { id: "label.add-board", defaultMessage: "Add board" }, + addLink: { id: "label.add-link", defaultMessage: "Add link" }, + addPixel: { id: "label.add-pixel", defaultMessage: "Add pixel" }, + maximize: { id: "label.maximize", defaultMessage: "Maximize" }, + remaining: { id: "label.remaining", defaultMessage: "Remaining" }, + conversion: { id: "label.conversion", defaultMessage: "Conversion" }, + firstClick: { id: "label.first-click", defaultMessage: "First click" }, + lastClick: { id: "label.last-click", defaultMessage: "Last click" }, + online: { id: "label.online", defaultMessage: "Online" }, + preferences: { id: "label.preferences", defaultMessage: "Preferences" }, + location: { id: "label.location", defaultMessage: "Location" }, + chart: { id: "label.chart", defaultMessage: "Chart" }, + table: { id: "label.table", defaultMessage: "Table" }, + download: { id: "label.download", defaultMessage: "Download" }, + traffic: { id: "label.traffic", defaultMessage: "Traffic" }, + behavior: { id: "label.behavior", defaultMessage: "Behavior" }, + growth: { id: "label.growth", defaultMessage: "Growth" }, + account: { id: "label.account", defaultMessage: "Account" }, + application: { id: "label.application", defaultMessage: "Application" }, + saveSegment: { id: "label.save-segment", defaultMessage: "Save as segment" }, + saveCohort: { id: "label.save-cohort", defaultMessage: "Save as cohort" }, + analysis: { id: "label.analysis", defaultMessage: "Analysis" }, + destinationUrl: { id: "label.destination-url", defaultMessage: "Destination URL" }, + audience: { id: "label.audience", defaultMessage: "Audience" }, + invalidUrl: { id: "label.invalid-url", defaultMessage: "Invalid URL" }, + environment: { id: "label.environment", defaultMessage: "Environment" }, + criteria: { id: "label.criteria", defaultMessage: "Criteria" }, + share: { id: "label.share", defaultMessage: "Share" }, + support: { id: "label.support", defaultMessage: "Support" }, + documentation: { id: "label.documentation", defaultMessage: "Documentation" }, + switchAccount: { id: "label.switch-account", defaultMessage: "Switch account" }, }); export const messages = defineMessages({ - error: { id: 'message.error', defaultMessage: 'Something went wrong.' }, - saved: { id: 'message.saved', defaultMessage: 'Saved successfully.' }, - noUsers: { id: 'message.no-users', defaultMessage: 'There are no users.' }, - userDeleted: { id: 'message.user-deleted', defaultMessage: 'User deleted.' }, - noDataAvailable: { id: 'message.no-data-available', defaultMessage: 'No data available.' }, - nothingSelected: { id: 'message.nothing-selected', defaultMessage: 'Nothing selected.' }, + error: { id: "message.error", defaultMessage: "Something went wrong." }, + saved: { id: "message.saved", defaultMessage: "Saved successfully." }, + noUsers: { id: "message.no-users", defaultMessage: "There are no users." }, + userDeleted: { id: "message.user-deleted", defaultMessage: "User deleted." }, + noDataAvailable: { id: "message.no-data-available", defaultMessage: "No data available." }, + nothingSelected: { id: "message.nothing-selected", defaultMessage: "Nothing selected." }, confirmReset: { - id: 'message.confirm-reset', - defaultMessage: 'Are you sure you want to reset {target}?', + id: "message.confirm-reset", + defaultMessage: "Are you sure you want to reset {target}?", }, confirmDelete: { - id: 'message.confirm-delete', - defaultMessage: 'Are you sure you want to delete {target}?', + id: "message.confirm-delete", + defaultMessage: "Are you sure you want to delete {target}?", }, confirmRemove: { - id: 'message.confirm-remove', - defaultMessage: 'Are you sure you want to remove {target}?', + id: "message.confirm-remove", + defaultMessage: "Are you sure you want to remove {target}?", }, confirmLeave: { - id: 'message.confirm-leave', - defaultMessage: 'Are you sure you want to leave {target}?', + id: "message.confirm-leave", + defaultMessage: "Are you sure you want to leave {target}?", }, minPasswordLength: { - id: 'message.min-password-length', - defaultMessage: 'Minimum length of {n} characters', + id: "message.min-password-length", + defaultMessage: "Minimum length of {n} characters", }, noTeams: { - id: 'message.no-teams', - defaultMessage: 'You have not created any teams.', + id: "message.no-teams", + defaultMessage: "You have not created any teams.", }, shareUrl: { - id: 'message.share-url', - defaultMessage: 'Your website stats are publicly available at the following URL:', + id: "message.share-url", + defaultMessage: "Your website stats are publicly available at the following URL:", }, trackingCode: { - id: 'message.tracking-code', - defaultMessage: - 'To track stats for this website, place the following code in the ... section of your HTML.', + id: "message.tracking-code", + defaultMessage: "To track stats for this website, place the following code in the ... section of your HTML.", }, joinTeamWarning: { - id: 'message.team-already-member', - defaultMessage: 'You are already a member of the team.', + id: "message.team-already-member", + defaultMessage: "You are already a member of the team.", }, actionConfirmation: { - id: 'message.action-confirmation', - defaultMessage: 'Type {confirmation} in the box below to confirm.', + id: "message.action-confirmation", + defaultMessage: "Type {confirmation} in the box below to confirm.", }, resetWebsite: { - id: 'message.reset-website', - defaultMessage: 'To reset this website, type {confirmation} in the box below to confirm.', + id: "message.reset-website", + defaultMessage: "To reset this website, type {confirmation} in the box below to confirm.", }, invalidDomain: { - id: 'message.invalid-domain', - defaultMessage: 'Invalid domain. Do not include http/https.', + id: "message.invalid-domain", + defaultMessage: "Invalid domain. Do not include http/https.", }, resetWebsiteWarning: { - id: 'message.reset-website-warning', - defaultMessage: - 'All statistics for this website will be deleted, but your settings will remain intact.', + id: "message.reset-website-warning", + defaultMessage: "All statistics for this website will be deleted, but your settings will remain intact.", }, deleteWebsiteWarning: { - id: 'message.delete-website-warning', - defaultMessage: 'All website data will be deleted.', + id: "message.delete-website-warning", + defaultMessage: "All website data will be deleted.", }, deleteTeamWarning: { - id: 'message.delete-team-warning', - defaultMessage: 'Deleting a team will also delete all team websites.', + id: "message.delete-team-warning", + defaultMessage: "Deleting a team will also delete all team websites.", }, noResultsFound: { - id: 'message.no-results-found', - defaultMessage: 'No results found.', + id: "message.no-results-found", + defaultMessage: "No results found.", }, noWebsitesConfigured: { - id: 'message.no-websites-configured', - defaultMessage: 'You do not have any websites configured.', + id: "message.no-websites-configured", + defaultMessage: "You do not have any websites configured.", }, noTeamWebsites: { - id: 'message.no-team-websites', - defaultMessage: 'This team does not have any websites.', + id: "message.no-team-websites", + defaultMessage: "This team does not have any websites.", }, teamWebsitesInfo: { - id: 'message.team-websites-info', - defaultMessage: 'Websites can be viewed by anyone on the team.', + id: "message.team-websites-info", + defaultMessage: "Websites can be viewed by anyone on the team.", }, - noMatchPassword: { id: 'message.no-match-password', defaultMessage: 'Passwords do not match.' }, + noMatchPassword: { id: "message.no-match-password", defaultMessage: "Passwords do not match." }, goToSettings: { - id: 'message.go-to-settings', - defaultMessage: 'Go to settings', + id: "message.go-to-settings", + defaultMessage: "Go to settings", }, activeUsers: { - id: 'message.active-users', - defaultMessage: '{x} current {x, plural, one {visitor} other {visitors}}', + id: "message.active-users", + defaultMessage: "{x} current {x, plural, one {visitor} other {visitors}}", }, teamNotFound: { - id: 'message.team-not-found', - defaultMessage: 'Team not found.', + id: "message.team-not-found", + defaultMessage: "Team not found.", }, visitorLog: { - id: 'message.visitor-log', - defaultMessage: 'Visitor from {country} using {browser} on {os} {device}', + id: "message.visitor-log", + defaultMessage: "Visitor from {country} using {browser} on {os} {device}", }, eventLog: { - id: 'message.event-log', - defaultMessage: '{event} on {url}', + id: "message.event-log", + defaultMessage: "{event} on {url}", }, incorrectUsernamePassword: { - id: 'message.incorrect-username-password', - defaultMessage: 'Incorrect username and/or password.', + id: "message.incorrect-username-password", + defaultMessage: "Incorrect username and/or password.", }, noEventData: { - id: 'message.no-event-data', - defaultMessage: 'No event data is available.', + id: "message.no-event-data", + defaultMessage: "No event data is available.", }, newVersionAvailable: { - id: 'message.new-version-available', - defaultMessage: 'A new version of Umami {version} is available!', + id: "message.new-version-available", + defaultMessage: "A new version of Syncfuse {version} is available!", }, transferWebsite: { - id: 'message.transfer-website', - defaultMessage: 'Transfer website ownership to your account or another team.', + id: "message.transfer-website", + defaultMessage: "Transfer website ownership to your account or another team.", }, transferTeamWebsiteToUser: { - id: 'message.transfer-team-website-to-user', - defaultMessage: 'Transfer this website to your account?', + id: "message.transfer-team-website-to-user", + defaultMessage: "Transfer this website to your account?", }, transferUserWebsiteToTeam: { - id: 'message.transfer-user-website-to-team', - defaultMessage: 'Select the team to transfer this website to.', + id: "message.transfer-user-website-to-team", + defaultMessage: "Select the team to transfer this website to.", }, unauthorized: { - id: 'message.unauthorized', - defaultMessage: 'Unauthorized', + id: "message.unauthorized", + defaultMessage: "Unauthorized", }, badRequest: { - id: 'message.bad-request', - defaultMessage: 'Bad request', + id: "message.bad-request", + defaultMessage: "Bad request", }, forbidden: { - id: 'message.forbidden', - defaultMessage: 'Forbidden', + id: "message.forbidden", + defaultMessage: "Forbidden", }, notFound: { - id: 'message.not-found', - defaultMessage: 'Not found', + id: "message.not-found", + defaultMessage: "Not found", }, serverError: { - id: 'message.sever-error', - defaultMessage: 'Server error', + id: "message.sever-error", + defaultMessage: "Server error", }, }); diff --git a/src/declaration.d.ts b/src/declaration.d.ts index 17acee2bb..f95f55f6a 100644 --- a/src/declaration.d.ts +++ b/src/declaration.d.ts @@ -1,23 +1,23 @@ -declare module '*.css'; -declare module '*.svg'; -declare module '*.json'; -declare module 'bcryptjs'; -declare module 'chartjs-adapter-date-fns'; -declare module 'cors'; -declare module 'date-fns-tz'; -declare module 'debug'; -declare module 'fs-extra'; -declare module 'jsonwebtoken'; -declare module 'md5'; -declare module 'papaparse'; -declare module 'prettier'; -declare module 'react-simple-maps'; -declare module 'semver'; -declare module 'tsup'; -declare module 'uuid'; -declare module '@umami/esbuild-plugin-css-modules'; +declare module "*.css"; +declare module "*.svg"; +declare module "*.json"; +declare module "bcryptjs"; +declare module "chartjs-adapter-date-fns"; +declare module "cors"; +declare module "date-fns-tz"; +declare module "debug"; +declare module "fs-extra"; +declare module "jsonwebtoken"; +declare module "md5"; +declare module "papaparse"; +declare module "prettier"; +declare module "react-simple-maps"; +declare module "semver"; +declare module "tsup"; +declare module "uuid"; +declare module "@umami/esbuild-plugin-css-modules"; -interface UmamiTracker { +interface SyncfuseTracker { track: { (): Promise; (eventName: string): Promise; @@ -29,5 +29,5 @@ interface UmamiTracker { } interface Window { - umami: UmamiTracker; + syncfuse: SyncfuseTracker; } diff --git a/src/lang/ar-SA.json b/src/lang/ar-SA.json index 5b5cfa9fb..cb4f12dda 100644 --- a/src/lang/ar-SA.json +++ b/src/lang/ar-SA.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "اسم المستخدم او كلمة المرور غير صحيحة.", "message.invalid-domain": "النطاق غير صحيح", "message.min-password-length": "اقل عدد مسموح به {n} حرف/أحرف", - "message.new-version-available": "إصدار جديد من Umami {version} متاح!", + "message.new-version-available": "إصدار جديد من Syncfuse {version} متاح!", "message.no-data-available": "لا توجد بيانات متاحة.", "message.no-event-data": "لا توجد بيانات الحدث متاحة.", "message.no-match-password": "كلمة المرور غير متطابقة", diff --git a/src/lang/be-BY.json b/src/lang/be-BY.json index 1a866a92e..9ee20675e 100644 --- a/src/lang/be-BY.json +++ b/src/lang/be-BY.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Некарэктнае імя карыстальніка/пароль.", "message.invalid-domain": "Некарэктны дамен", "message.min-password-length": "Мінімальная даўжыня {n} знакаў", - "message.new-version-available": "Даступная новая версія Umami {version}!", + "message.new-version-available": "Даступная новая версія Syncfuse {version}!", "message.no-data-available": "Няма дадзеных.", "message.no-event-data": "Дадзеныя падзеі недаступныя.", "message.no-match-password": "Паролі не супадаюць", diff --git a/src/lang/bg-BG.json b/src/lang/bg-BG.json index 4b0effc89..91d222b7d 100644 --- a/src/lang/bg-BG.json +++ b/src/lang/bg-BG.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Неправилно потребителско име и/или парола.", "message.invalid-domain": "Невалиден домейн. Не включвайте http/https.", "message.min-password-length": "Минимална дължина от {n} символа", - "message.new-version-available": "Има нова версия на Umami {version}!", + "message.new-version-available": "Има нова версия на Syncfuse {version}!", "message.no-data-available": "Няма налични данни.", "message.no-event-data": "Няма налични данни за събитие.", "message.no-match-password": "Паролите не съвпадат.", diff --git a/src/lang/bn-BD.json b/src/lang/bn-BD.json index 9b9ad2f43..ae12c659b 100644 --- a/src/lang/bn-BD.json +++ b/src/lang/bn-BD.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "ভুল ব্যবহারকারীর নাম/পাসওয়ার্ড।", "message.invalid-domain": "ভুল ডোমেন", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "কোন তথ্য নেই।", "message.no-event-data": "No event data is available.", "message.no-match-password": "পাসওয়ার্ড মেলে না", diff --git a/src/lang/bs-BA.json b/src/lang/bs-BA.json index 56848771b..25560a2a7 100644 --- a/src/lang/bs-BA.json +++ b/src/lang/bs-BA.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Pogrešno korisničko ime i/ili šifra.", "message.invalid-domain": "Nevalidna domena. Ne uključujte http/https.", "message.min-password-length": "Minimalna dužina od {n} karaktera", - "message.new-version-available": "Nova verzija Umami {version} je dostupna!", + "message.new-version-available": "Nova verzija Syncfuse {version} je dostupna!", "message.no-data-available": "Nema dostupnih podataka.", "message.no-event-data": "Nema dostupnih podataka o događajima.", "message.no-match-password": "Šifre se ne poklapaju.", diff --git a/src/lang/ca-ES.json b/src/lang/ca-ES.json index ab5444ceb..35d82e599 100644 --- a/src/lang/ca-ES.json +++ b/src/lang/ca-ES.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nom d'usuari o contrasenya incorrectes.", "message.invalid-domain": "Domini invàlid", "message.min-password-length": "Longitud mínima de {n} caràcters", - "message.new-version-available": "Una nova versió d'Umami {version} està disponible!", + "message.new-version-available": "Una nova versió d'Syncfuse {version} està disponible!", "message.no-data-available": "No hi ha dades disponibles.", "message.no-event-data": "No hi ha dades d'esdeveniments disponibles.", "message.no-match-password": "Les contrasenyes no coincideixen", diff --git a/src/lang/cs-CZ.json b/src/lang/cs-CZ.json index 77d45a79f..4221fb8f1 100644 --- a/src/lang/cs-CZ.json +++ b/src/lang/cs-CZ.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nesprávné jméno/heslo.", "message.invalid-domain": "Neplatná doména", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Žádná data.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Hesla se neschodují", diff --git a/src/lang/da-DK.json b/src/lang/da-DK.json index f6c447ff5..3bd79e438 100644 --- a/src/lang/da-DK.json +++ b/src/lang/da-DK.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Ugyldigt brugernavn/adgangskode.", "message.invalid-domain": "Ugyldigt domæne", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Ingen data tilgængelig.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Adgangskoderne matcher ikke", diff --git a/src/lang/de-CH.json b/src/lang/de-CH.json index 55734ebdf..d592f3eba 100644 --- a/src/lang/de-CH.json +++ b/src/lang/de-CH.json @@ -307,7 +307,7 @@ "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": "Es isch en neue Version vo Umami {version} verfügbar!", + "message.new-version-available": "Es isch en neue Version vo Syncfuse {version} verfügbar!", "message.no-data-available": "Kei Date vorhande.", "message.no-event-data": "Es sind kei Event Date verfügbar.", "message.no-match-password": "Passwörter stimmed ned überi", diff --git a/src/lang/de-DE.json b/src/lang/de-DE.json index 3436eb89e..026287190 100644 --- a/src/lang/de-DE.json +++ b/src/lang/de-DE.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Falsches Passwort oder Benutzername.", "message.invalid-domain": "Ungültige Domain", "message.min-password-length": "Minimale Länge von {n} Zeichen", - "message.new-version-available": "Eine neue Version von Umami ist verfügbar: {version}", + "message.new-version-available": "Eine neue Version von Syncfuse ist verfügbar: {version}", "message.no-data-available": "Keine Daten vorhanden.", "message.no-event-data": "Es sind keine Ereignisdaten verfügbar.", "message.no-match-password": "Passwörter stimmen nicht überein", diff --git a/src/lang/el-GR.json b/src/lang/el-GR.json index 720ff5ea1..93c0a456a 100644 --- a/src/lang/el-GR.json +++ b/src/lang/el-GR.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Εσφαλμένο όνομα χρήστη / κωδικός πρόσβασης.", "message.invalid-domain": "Μη έγκυρος τομέας", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Δεν υπάρχουν διαθέσιμα δεδομένα.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Οι κωδικοί πρόσβασης δεν ταιριάζουν", diff --git a/src/lang/en-GB.json b/src/lang/en-GB.json index 7803dd68e..b8429f974 100644 --- a/src/lang/en-GB.json +++ b/src/lang/en-GB.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Incorrect username/password.", "message.invalid-domain": "Invalid domain", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "No data available.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Passwords don't match", diff --git a/src/lang/en-US.json b/src/lang/en-US.json index 3e588f50d..20ee34acc 100644 --- a/src/lang/en-US.json +++ b/src/lang/en-US.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Incorrect username and/or password.", "message.invalid-domain": "Invalid domain. Do not include http/https.", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "No data available.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Passwords do not match.", diff --git a/src/lang/es-ES.json b/src/lang/es-ES.json index e3a4d38d3..a14ae01e4 100644 --- a/src/lang/es-ES.json +++ b/src/lang/es-ES.json @@ -308,7 +308,7 @@ "message.incorrect-username-password": "Nombre de usuario o contraseña incorrectos.", "message.invalid-domain": "Dominio inválido", "message.min-password-length": "Longitud mínima de {n} caracteres", - "message.new-version-available": "Una nueva versión de Umami {version} está disponible", + "message.new-version-available": "Una nueva versión de Syncfuse {version} está disponible", "message.no-data-available": "No hay información disponible.", "message.no-event-data": "No hay datos de eventos disponibles.", "message.no-match-password": "Las contraseñas no coinciden", diff --git a/src/lang/fa-IR.json b/src/lang/fa-IR.json index 96b3da9bf..34d06d7d4 100644 --- a/src/lang/fa-IR.json +++ b/src/lang/fa-IR.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "نام کاربری / رمز نادرست است.", "message.invalid-domain": "دامنه نامعتبر است.", "message.min-password-length": "حداقل طول {n} کاراکتر است.", - "message.new-version-available": "نسخه‌ی جدیدی از Umami {version} در دسترس است.", + "message.new-version-available": "نسخه‌ی جدیدی از Syncfuse {version} در دسترس است.",, "message.no-data-available": "اطلاعاتی موجود نیست.", "message.no-event-data": "هیچ داده‌ای برای این رویداد وجود ندارد.", "message.no-match-password": "رمزها یکسان نیستند", diff --git a/src/lang/fi-FI.json b/src/lang/fi-FI.json index daaa62f0d..c0aeced94 100644 --- a/src/lang/fi-FI.json +++ b/src/lang/fi-FI.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Väärä käyttäjänimi/salasana.", "message.invalid-domain": "Virheellinen verkkotunnus", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Tietoja ei ole käytettävissä.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Salasanat eivät täsmää", diff --git a/src/lang/fo-FO.json b/src/lang/fo-FO.json index 6fca42586..886a1b88d 100644 --- a/src/lang/fo-FO.json +++ b/src/lang/fo-FO.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Skeivt brúkaranavn/loyniorð.", "message.invalid-domain": "Ógilt økisnavn", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Einki data tøk.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Loyniorðini eru ikki eins", diff --git a/src/lang/fr-FR.json b/src/lang/fr-FR.json index cd6a96bc3..6b306cfb6 100644 --- a/src/lang/fr-FR.json +++ b/src/lang/fr-FR.json @@ -309,7 +309,7 @@ "message.incorrect-username-password": "Nom d'utilisateur/Mot de passe incorrect.", "message.invalid-domain": "Domaine invalide", "message.min-password-length": "Taille minimale de {n} caractères", - "message.new-version-available": "Une nouvelle version d'Umami {version} est disponible !", + "message.new-version-available": "Une nouvelle version d'Syncfuse {version} est disponible !", "message.no-data-available": "Aucune donnée disponible.", "message.no-event-data": "Aucune donnée d'événement disponible.", "message.no-match-password": "Les mots de passe ne correspondent pas", diff --git a/src/lang/ga-ES.json b/src/lang/ga-ES.json index 208260059..88d75e9ec 100644 --- a/src/lang/ga-ES.json +++ b/src/lang/ga-ES.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Credenciais incorrectas.", "message.invalid-domain": "Dominio non válido", "message.min-password-length": "Lonxitude mínima de {n} caracteres", - "message.new-version-available": "Unha nova versión de Umami {version} está dispoñible!", + "message.new-version-available": "Unha nova versión de Syncfuse {version} está dispoñible!", "message.no-data-available": "Sen datos dispoñibles.", "message.no-event-data": "Sen datos de eventos dispoñibles.", "message.no-match-password": "Non concordan os contrasinais", diff --git a/src/lang/he-IL.json b/src/lang/he-IL.json index 2d115c8d7..400e7e2af 100644 --- a/src/lang/he-IL.json +++ b/src/lang/he-IL.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "שם משתמש או סיסמה לא נכונים", "message.invalid-domain": "דומיין לא תקין", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "אין מידע זמין", "message.no-event-data": "No event data is available.", "message.no-match-password": "סיסמאות לא תואמות", diff --git a/src/lang/hi-IN.json b/src/lang/hi-IN.json index 54cac3012..2a2a2cf59 100644 --- a/src/lang/hi-IN.json +++ b/src/lang/hi-IN.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "ग़लत उपयोगकर्ता नाम / पासवर्ड।", "message.invalid-domain": "अमान्य डोमेन", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "कोई डेटा उपलब्ध नहीं है।", "message.no-event-data": "No event data is available.", "message.no-match-password": "पासवर्ड मेल नहीं खाते", diff --git a/src/lang/hr-HR.json b/src/lang/hr-HR.json index 141ad3fdd..29718ec08 100644 --- a/src/lang/hr-HR.json +++ b/src/lang/hr-HR.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Neispravno korisničke ime/lozinka.", "message.invalid-domain": "Invalid domain. Do not include http/https.", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Nema dostupnih podataka.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Passwords do not match.", diff --git a/src/lang/hu-HU.json b/src/lang/hu-HU.json index 1666b7a11..53b08500c 100644 --- a/src/lang/hu-HU.json +++ b/src/lang/hu-HU.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Érvénytelen felhasználónév/jelszó.", "message.invalid-domain": "Érvénytelen domain", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Nincs rendelkezésre álló adat.", "message.no-event-data": "No event data is available.", "message.no-match-password": "A jelszavak nem egyeznek", diff --git a/src/lang/id-ID.json b/src/lang/id-ID.json index 30a64b6cb..595e90010 100644 --- a/src/lang/id-ID.json +++ b/src/lang/id-ID.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nama pengguna/kata sandi salah.", "message.invalid-domain": "Domain tidak valid", "message.min-password-length": "Minimal {n} karakter", - "message.new-version-available": "Versi baru dari Umami {version} telah tersedia!", + "message.new-version-available": "Versi baru dari Syncfuse {version} telah tersedia!", "message.no-data-available": "Tidak ada data.", "message.no-event-data": "Tidak ada data peristiwa", "message.no-match-password": "Kata sandi tidak cocok", diff --git a/src/lang/it-IT.json b/src/lang/it-IT.json index 40cb5ecda..0321aa088 100644 --- a/src/lang/it-IT.json +++ b/src/lang/it-IT.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Username o password non corretti.", "message.invalid-domain": "Dominio non valido", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Nessun dato disponibile.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Le password non corrispondono", diff --git a/src/lang/ja-JP.json b/src/lang/ja-JP.json index 7d2bf4030..c7545a827 100644 --- a/src/lang/ja-JP.json +++ b/src/lang/ja-JP.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "ユーザー名またはパスワードが間違っています。", "message.invalid-domain": "無効なドメインです。http/httpsを含めないでください。", "message.min-password-length": "最小文字数は{n}文字です", - "message.new-version-available": "Umamiの新しいバージョン{version}が利用可能です!", + "message.new-version-available": "Syncfuseの新しいバージョン{version}が利用可能です!", "message.no-data-available": "データがありません。", "message.no-event-data": "イベントデータがありません。", "message.no-match-password": "パスワードが一致しません。", diff --git a/src/lang/km-KH.json b/src/lang/km-KH.json index 087e24dc5..796c7bbc1 100644 --- a/src/lang/km-KH.json +++ b/src/lang/km-KH.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "ឈ្មោះអ្នកប្រើឬពាក្យសម្ងាត់មិនត្រឹមត្រូវ។", "message.invalid-domain": "Domain មិន​ត្រឹមត្រូវ", "message.min-password-length": "តិចបំផុតដែលមានអក្សរ {n} តួអក្សរ", - "message.new-version-available": "Version ថ្មីនៃ Umami {version} អាចប្រើប្រាស់បានហើយ!", + "message.new-version-available": "Version ថ្មីនៃ Syncfuse {version} អាចប្រើប្រាស់បានហើយ!", "message.no-data-available": "មិនមានទិន្នន័យ។", "message.no-event-data": "មិនមានទិន្នន័យព្រឹត្តិការណ៍ទេ។", "message.no-match-password": "ពាក្យសម្ងាត់មិនត្រូវគ្នាទេ។", diff --git a/src/lang/ko-KR.json b/src/lang/ko-KR.json index 977eea4e2..9af7f07c1 100644 --- a/src/lang/ko-KR.json +++ b/src/lang/ko-KR.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "사용자 이름 또는 비밀번호를 잘못 입력했습니다.", "message.invalid-domain": "잘못된 도메인입니다. http/https를 포함하지 마세요.", "message.min-password-length": "최소 {n}자여야 합니다", - "message.new-version-available": "Umami의 새 버전 {version}을(를) 사용할 수 있습니다!", + "message.new-version-available": "Syncfuse의 새 버전 {version}을(를) 사용할 수 있습니다!",, "message.no-data-available": "사용할 수 있는 데이터가 없습니다.", "message.no-event-data": "사용할 수 있는 이벤트 데이터가 없습니다.", "message.no-match-password": "비밀번호가 일치하지 않습니다.", diff --git a/src/lang/lt-LT.json b/src/lang/lt-LT.json index 772fa34e4..56965d6ab 100644 --- a/src/lang/lt-LT.json +++ b/src/lang/lt-LT.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Neteisingas vartotojo vardas/slaptažodis.", "message.invalid-domain": "Klaidingas domenas", "message.min-password-length": "Reikia bent {n} simbolių", - "message.new-version-available": "Išleista nauja 'Umami' {version} versija!", + "message.new-version-available": "Išleista nauja 'Syncfuse' {version} versija!", "message.no-data-available": "Nėra jokių duomenų.", "message.no-event-data": "Jokių duomenų apie įvykius nėra.", "message.no-match-password": "Slaptažodžiai nesutampa", diff --git a/src/lang/mn-MN.json b/src/lang/mn-MN.json index e9c649dbd..05e242ad4 100644 --- a/src/lang/mn-MN.json +++ b/src/lang/mn-MN.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Буруу хэрэглэгчийн нэр/нууц үг.", "message.invalid-domain": "Буруу домэйн", "message.min-password-length": "Хамгийн багадаа {n} тэмдэгт", - "message.new-version-available": "Umami-н шинэ хувилбар {version} гарсан байна!", + "message.new-version-available": "Syncfuse-н шинэ хувилбар {version} гарсан байна!",, "message.no-data-available": "Өгөгдөл алга.", "message.no-event-data": "Үйлдлийн өгөгдөл алга.", "message.no-match-password": "Нууц үг тохирохгүй байна.", diff --git a/src/lang/ms-MY.json b/src/lang/ms-MY.json index 32abd0850..e8c63c1c4 100644 --- a/src/lang/ms-MY.json +++ b/src/lang/ms-MY.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Pengguna/kata laluan tidak betul.", "message.invalid-domain": "Domain tidak sah", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Tiada data yang boleh didapati.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Kata laluan tidak sepadan", diff --git a/src/lang/nb-NO.json b/src/lang/nb-NO.json index adb4468e3..0129f7f86 100644 --- a/src/lang/nb-NO.json +++ b/src/lang/nb-NO.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Ugyldig brukernavn/passord.", "message.invalid-domain": "Ugyldig domene", "message.min-password-length": "Minimumslengde på {n} tegn", - "message.new-version-available": "En ny versjon av Umami {version} er tilgjengelig!", + "message.new-version-available": "En ny versjon av Syncfuse {version} er tilgjengelig!", "message.no-data-available": "Ingen data tilgjengelig.", "message.no-event-data": "Ingen hendelsesdata er tilgjengelig.", "message.no-match-password": "Passordene er ikke like", diff --git a/src/lang/nl-NL.json b/src/lang/nl-NL.json index 1ec5c0203..df0f9f1d7 100644 --- a/src/lang/nl-NL.json +++ b/src/lang/nl-NL.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Incorrecte gebruikersnaam/wachtwoord.", "message.invalid-domain": "Ongeldig domein", "message.min-password-length": "Minimale lengte van {n} tekens", - "message.new-version-available": "Een nieuwe versie van Umami {version} is beschikbaar!", + "message.new-version-available": "Een nieuwe versie van Syncfuse {version} is beschikbaar!", "message.no-data-available": "Geen gegevens beschikbaar.", "message.no-event-data": "Geen gegevens over de gebeurtenis beschikbaar.", "message.no-match-password": "Wachtwoorden komen niet overeen", diff --git a/src/lang/pl-PL.json b/src/lang/pl-PL.json index 0c8b00043..15f372115 100644 --- a/src/lang/pl-PL.json +++ b/src/lang/pl-PL.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nieprawidłowa nazwa użytkownika lub hasło.", "message.invalid-domain": "Nieprawidłowa witryna", "message.min-password-length": "Minimalna długość {n} znaków", - "message.new-version-available": "Nowa wersja Umami {version} jest dostępna!", + "message.new-version-available": "Nowa wersja Syncfuse {version} jest dostępna!", "message.no-data-available": "Brak dostępnych danych.", "message.no-event-data": "Brak dostępnych danych o zdarzeniach.", "message.no-match-password": "Hasła się nie zgadzają", diff --git a/src/lang/pt-BR.json b/src/lang/pt-BR.json index c34c9ab05..edef7a8d4 100644 --- a/src/lang/pt-BR.json +++ b/src/lang/pt-BR.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nome de usuário ou senha incorretos.", "message.invalid-domain": "Domínio inválido", "message.min-password-length": "A senha deve ter no mínimo {n} caracteres", - "message.new-version-available": "Uma nova versão {version} do Umami está disponível!", + "message.new-version-available": "Uma nova versão {version} do Syncfuse está disponível!", "message.no-data-available": "Não há dados disponíveis.", "message.no-event-data": "Não há eventos disponíveis.", "message.no-match-password": "As senhas não coincidem.", diff --git a/src/lang/pt-PT.json b/src/lang/pt-PT.json index 86734cb5d..921eef996 100644 --- a/src/lang/pt-PT.json +++ b/src/lang/pt-PT.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nome de utilizador/senha incorretos.", "message.invalid-domain": "Domínio inválido", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Sem dados disponíveis.", "message.no-event-data": "No event data is available.", "message.no-match-password": "As senhas não coincidem", diff --git a/src/lang/ro-RO.json b/src/lang/ro-RO.json index 786333049..4ad4410fc 100644 --- a/src/lang/ro-RO.json +++ b/src/lang/ro-RO.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nume utilizator / parolă incorecte.", "message.invalid-domain": "Domeniul nu este valid", "message.min-password-length": "Lungimea minimă este de {n} caractere", - "message.new-version-available": "O nouă versiune de Umami {version} este disponibilă!", + "message.new-version-available": "O nouă versiune de Syncfuse {version} este disponibilă!", "message.no-data-available": "Nicio informație disponibilă.", "message.no-event-data": "Nu sunt disponibile date legate de eveniment.", "message.no-match-password": "Parolele nu se potrivesc", diff --git a/src/lang/ru-RU.json b/src/lang/ru-RU.json index 96d0538fb..3cb7181d5 100644 --- a/src/lang/ru-RU.json +++ b/src/lang/ru-RU.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Неверное имя пользователя/пароль.", "message.invalid-domain": "Некорректный домен", "message.min-password-length": "Минимальная длина {n} символов", - "message.new-version-available": "Вышла новая версия Umami {version}!", + "message.new-version-available": "Вышла новая версия Syncfuse {version}!", "message.no-data-available": "Нет данных.", "message.no-event-data": "Данные о событиях отсутствуют.", "message.no-match-password": "Пароли не совпадают", diff --git a/src/lang/si-LK.json b/src/lang/si-LK.json index 3e6aff86c..85c34f1bb 100644 --- a/src/lang/si-LK.json +++ b/src/lang/si-LK.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "වැරදි පරිශීලක නාමය/මුරපදය.", "message.invalid-domain": "Invalid domain. Do not include http/https.", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "පෙන්වීමට දත්ත නොමැත.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Passwords do not match.", diff --git a/src/lang/sk-SK.json b/src/lang/sk-SK.json index 297d5e341..8cc60b375 100644 --- a/src/lang/sk-SK.json +++ b/src/lang/sk-SK.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Nesprávné meno/heslo.", "message.invalid-domain": "Neplatná doména", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "Žiadne data.", "message.no-event-data": "No event data is available.", "message.no-match-password": "Hesla se nezhodujú", diff --git a/src/lang/sl-SI.json b/src/lang/sl-SI.json index 3dd3226f6..d4b3593bc 100644 --- a/src/lang/sl-SI.json +++ b/src/lang/sl-SI.json @@ -286,7 +286,7 @@ "message.incorrect-username-password": "Nepravilno uporabniško ime/geslo.", "message.invalid-domain": "Neveljavna domena", "message.min-password-length": "Najmanjša dolžina je {n} znakov", - "message.new-version-available": "Na voljo je nova verzija programa Umami {version}!", + "message.new-version-available": "Na voljo je nova verzija programa Syncfuse {version}!", "message.no-data-available": "Podatki niso na voljo.", "message.no-event-data": "Podatki o dogodku niso na voljo.", "message.no-match-password": "Gesli se ne ujemata", diff --git a/src/lang/sv-SE.json b/src/lang/sv-SE.json index 1f456b0e7..a4a585c67 100644 --- a/src/lang/sv-SE.json +++ b/src/lang/sv-SE.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Felaktigt användarnamn/lösenord.", "message.invalid-domain": "Ogiltig domän", "message.min-password-length": "Minst {n} tecken", - "message.new-version-available": "En ny version av Umami {version} är tillgänglig!", + "message.new-version-available": "En ny version av Syncfuse {version} är tillgänglig!",, "message.no-data-available": "Ingen data tillgänglig.", "message.no-event-data": "Ingen händelsedata är tillgänglig.", "message.no-match-password": "Lösenorden matchar inte", diff --git a/src/lang/ta-IN.json b/src/lang/ta-IN.json index 9e33d7b6a..20b957346 100644 --- a/src/lang/ta-IN.json +++ b/src/lang/ta-IN.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "தவறான பயனர்பெயர் / கடவுச்சொல்.", "message.invalid-domain": "தவறான கள முகவரி", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "தரவு எதுவும் கிடைக்கவில்லை.", "message.no-event-data": "No event data is available.", "message.no-match-password": "இருக்கடவுச்சொல் பொருந்தவில்லை", diff --git a/src/lang/th-TH.json b/src/lang/th-TH.json index b94ca9051..74804c9b7 100644 --- a/src/lang/th-TH.json +++ b/src/lang/th-TH.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง.", "message.invalid-domain": "โดเมนไม่ถูกต้อง", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "ไม่มีข้อมูล.", "message.no-event-data": "No event data is available.", "message.no-match-password": "รหัสผ่านไม่ตรงกัน", diff --git a/src/lang/tr-TR.json b/src/lang/tr-TR.json index 3a2dce4b8..6c68140ee 100644 --- a/src/lang/tr-TR.json +++ b/src/lang/tr-TR.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Hatalı kullanıcı adı ya da parola.", "message.invalid-domain": "Geçersiz alan adı", "message.min-password-length": "Minimum {n} karakter uzunluğu", - "message.new-version-available": "Yeni versiyon Umami {version} mevcut!", + "message.new-version-available": "Yeni versiyon Syncfuse {version} mevcut!", "message.no-data-available": "Henüz hiç veri yok.", "message.no-event-data": "Hiçbir olay verisi mevcut değil.", "message.no-match-password": "Parolalar uyuşmuyor", diff --git a/src/lang/uk-UA.json b/src/lang/uk-UA.json index 768015bed..2c848858e 100644 --- a/src/lang/uk-UA.json +++ b/src/lang/uk-UA.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "Невірне ім'я користувача або пароль.", "message.invalid-domain": "Некоректний домен", "message.min-password-length": "Мінімальна довжина {n} символів", - "message.new-version-available": "Вийшла нова версія Umami {version}!", + "message.new-version-available": "Вийшла нова версія Syncfuse {version}!", "message.no-data-available": "Немає даних.", "message.no-event-data": "Дані про події відсутні.", "message.no-match-password": "Паролі не співпадають", diff --git a/src/lang/ur-PK.json b/src/lang/ur-PK.json index 5cc31212c..ba71ec65d 100644 --- a/src/lang/ur-PK.json +++ b/src/lang/ur-PK.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "غلط صارف نام/پاس ورڈ۔", "message.invalid-domain": "غلط ڈومین", "message.min-password-length": "Minimum length of {n} characters", - "message.new-version-available": "A new version of Umami {version} is available!", + "message.new-version-available": "A new version of Syncfuse {version} is available!", "message.no-data-available": "مواد موجود نہیں ہے.", "message.no-event-data": "No event data is available.", "message.no-match-password": "پاس ورڈز مماثل نہیں ہیں", diff --git a/src/lang/uz-UZ.json b/src/lang/uz-UZ.json index cf58945f4..75545fb60 100644 --- a/src/lang/uz-UZ.json +++ b/src/lang/uz-UZ.json @@ -251,7 +251,7 @@ "message.incorrect-username-password": "Notoʻgʻri foydalanuvchi nomi va/yoki parol.", "message.invalid-domain": "Notoʻgʻri domen. http/https qoʻshmang.", "message.min-password-length": "Minimal uzunligi {n} belgidan", - "message.new-version-available": "Umami'ning yangi **{version}** versiyasi mavjud!", + "message.new-version-available": "Syncfuse'ning yangi **{version}** versiyasi mavjud!",, "message.no-data-available": "Ma'lumotlar mavjud emas.", "message.no-event-data": "Hodisa ma'lumotlari mavjud emas.", "message.no-match-password": "Parollar mos kelmadi.", diff --git a/src/lang/vi-VN.json b/src/lang/vi-VN.json index fc0a8c139..185165cd5 100644 --- a/src/lang/vi-VN.json +++ b/src/lang/vi-VN.json @@ -251,7 +251,7 @@ "message.incorrect-username-password": "Sai tên đăng nhập/mật khẩu.", "message.invalid-domain": "Tên miền không hợp lệ", "message.min-password-length": "Độ dài tối thiểu {n} ký tự", - "message.new-version-available": "Có phiên bản mới của Umami {version}!", + "message.new-version-available": "Có phiên bản mới của Syncfuse {version}!", "message.no-data-available": "Không có dữ liệu.", "message.no-event-data": "Không có dữ liệu sự kiện.", "message.no-match-password": "Mật khẩu không khớp", diff --git a/src/lang/zh-CN.json b/src/lang/zh-CN.json index c6f01dd5c..e9421b4d6 100644 --- a/src/lang/zh-CN.json +++ b/src/lang/zh-CN.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "用户名或密码不正确。", "message.invalid-domain": "无效域名", "message.min-password-length": "密码最短长度为 {n} 个字符", - "message.new-version-available": "Umami 新版本 {version} 已发布!", + "message.new-version-available": "Syncfuse 新版本 {version} 已发布!", "message.no-data-available": "暂无数据。", "message.no-event-data": "无可用事件。", "message.no-match-password": "密码不一致", diff --git a/src/lang/zh-TW.json b/src/lang/zh-TW.json index 030d11dce..0118efdba 100644 --- a/src/lang/zh-TW.json +++ b/src/lang/zh-TW.json @@ -307,7 +307,7 @@ "message.incorrect-username-password": "使用者名稱或密碼不正確。", "message.invalid-domain": "無效的網域。請勿包含 http/https。", "message.min-password-length": "密碼長度至少需 {n} 個字元", - "message.new-version-available": "Umami {version} 的新版本已推出!", + "message.new-version-available": "Syncfuse {version} 的新版本已推出!", "message.no-data-available": "沒有可用的資料。", "message.no-event-data": "沒有可用的事件資料。", "message.no-match-password": "密碼不一致。", diff --git a/src/lib/auth.ts b/src/lib/auth.ts index ba6d8b09f..f0059dd05 100644 --- a/src/lib/auth.ts +++ b/src/lib/auth.ts @@ -1,18 +1,18 @@ -import debug from 'debug'; -import { ROLE_PERMISSIONS, ROLES, SHARE_TOKEN_HEADER } from '@/lib/constants'; -import { secret } from '@/lib/crypto'; -import { getRandomChars } from '@/lib/generate'; -import { createSecureToken, parseSecureToken, parseToken } from '@/lib/jwt'; -import redis from '@/lib/redis'; -import { ensureArray } from '@/lib/utils'; -import { getUser } from '@/queries/prisma/user'; +import debug from "debug"; +import { ROLE_PERMISSIONS, ROLES, SHARE_TOKEN_HEADER } from "@/lib/constants"; +import { secret } from "@/lib/crypto"; +import { getRandomChars } from "@/lib/generate"; +import { createSecureToken, parseSecureToken, parseToken } from "@/lib/jwt"; +import redis from "@/lib/redis"; +import { ensureArray } from "@/lib/utils"; +import { getUser } from "@/queries/prisma/user"; -const log = debug('umami:auth'); +const log = debug("syncfuse:auth"); export function getBearerToken(request: Request) { - const auth = request.headers.get('authorization'); + const auth = request.headers.get("authorization"); - return auth?.split(' ')[1]; + return auth?.split(" ")[1]; } export async function checkAuth(request: Request) { @@ -36,7 +36,7 @@ export async function checkAuth(request: Request) { log({ token, payload, authKey, shareToken, user }); if (!user?.id && !shareToken) { - log('User not authorized'); + log("User not authorized"); return null; } @@ -67,7 +67,7 @@ export async function saveAuth(data: any, expire = 0) { } export async function hasPermission(role: string, permission: string | string[]) { - return ensureArray(permission).some(e => ROLE_PERMISSIONS[role]?.includes(e)); + return ensureArray(permission).some((e) => ROLE_PERMISSIONS[role]?.includes(e)); } export function parseShareToken(request: Request) { diff --git a/src/lib/clickhouse.ts b/src/lib/clickhouse.ts index f2ebbb722..a6f6c1503 100644 --- a/src/lib/clickhouse.ts +++ b/src/lib/clickhouse.ts @@ -1,57 +1,50 @@ -import { type ClickHouseClient, createClient } from '@clickhouse/client'; -import { formatInTimeZone } from 'date-fns-tz'; -import debug from 'debug'; -import { CLICKHOUSE } from '@/lib/db'; -import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS } from './constants'; -import { filtersObjectToArray } from './params'; -import type { QueryFilters, QueryOptions } from './types'; +import { type ClickHouseClient, createClient } from "@clickhouse/client"; +import { formatInTimeZone } from "date-fns-tz"; +import debug from "debug"; +import { CLICKHOUSE } from "@/lib/db"; +import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS } from "./constants"; +import { filtersObjectToArray } from "./params"; +import type { QueryFilters, QueryOptions } from "./types"; export const CLICKHOUSE_DATE_FORMATS = { - utc: '%Y-%m-%dT%H:%i:%SZ', - second: '%Y-%m-%d %H:%i:%S', - minute: '%Y-%m-%d %H:%i:00', - hour: '%Y-%m-%d %H:00:00', - day: '%Y-%m-%d', - month: '%Y-%m-01', - year: '%Y-01-01', + utc: "%Y-%m-%dT%H:%i:%SZ", + second: "%Y-%m-%d %H:%i:%S", + minute: "%Y-%m-%d %H:%i:00", + hour: "%Y-%m-%d %H:00:00", + day: "%Y-%m-%d", + month: "%Y-%m-01", + year: "%Y-01-01", }; -const log = debug('umami:clickhouse'); +const log = debug("syncfuse:clickhouse"); let clickhouse: ClickHouseClient; const enabled = Boolean(process.env.CLICKHOUSE_URL); function getClient() { - const { - hostname, - port, - pathname, - protocol, - username = 'default', - password, - } = new URL(process.env.CLICKHOUSE_URL); + const { hostname, port, pathname, protocol, username = "default", password } = new URL(process.env.CLICKHOUSE_URL); const client = createClient({ url: `${protocol}//${hostname}:${port}`, - database: pathname.replace('/', ''), + database: pathname.replace("/", ""), username: username, password, }); - if (process.env.NODE_ENV !== 'production') { + if (process.env.NODE_ENV !== "production") { globalThis[CLICKHOUSE] = client; } - log('Clickhouse initialized'); + log("Clickhouse initialized"); return client; } function getUTCString(date?: Date | string | number) { - return formatInTimeZone(date || new Date(), 'UTC', 'yyyy-MM-dd HH:mm:ss'); + return formatInTimeZone(date || new Date(), "UTC", "yyyy-MM-dd HH:mm:ss"); } -function getDateStringSQL(data: any, unit: string = 'utc', timezone?: string) { +function getDateStringSQL(data: any, unit: string = "utc", timezone?: string) { if (timezone) { return `formatDateTime(${data}, '${CLICKHOUSE_DATE_FORMATS[unit]}', '${timezone}')`; } @@ -66,11 +59,11 @@ function getDateSQL(field: string, unit: string, timezone?: string) { return `toDateTime(date_trunc('${unit}', ${field}))`; } -function getSearchSQL(column: string, param: string = 'search'): string { +function getSearchSQL(column: string, param: string = "search"): string { return `and positionCaseInsensitive(${column}, {${param}:String}) > 0`; } -function mapFilter(column: string, operator: string, name: string, type: string = 'String') { +function mapFilter(column: string, operator: string, name: string, type: string = "String") { const value = `{${name}:${type}}`; switch (operator) { @@ -83,7 +76,7 @@ function mapFilter(column: string, operator: string, name: string, type: string case OPERATORS.doesNotContain: return `positionCaseInsensitive(${column}, ${value}) = 0`; default: - return ''; + return ""; } } @@ -92,17 +85,17 @@ function getFilterQuery(filters: Record, options: QueryOptions = {} const isCohort = options?.isCohort; if (isCohort) { - column = FILTER_COLUMNS[name.slice('cohort_'.length)]; + column = FILTER_COLUMNS[name.slice("cohort_".length)]; } if (column) { - if (name === 'eventType') { - arr.push(`and ${mapFilter(column, operator, name, 'UInt32')}`); + if (name === "eventType") { + arr.push(`and ${mapFilter(column, operator, name, "UInt32")}`); } else { arr.push(`and ${mapFilter(column, operator, name)}`); } - if (name === 'referrer') { + if (name === "referrer") { arr.push(`and referrer_domain != hostname`); } } @@ -110,12 +103,12 @@ function getFilterQuery(filters: Record, options: QueryOptions = {} return arr; }, []); - return query.join('\n'); + return query.join("\n"); } function getCohortQuery(filters: Record) { if (!filters || Object.keys(filters).length === 0) { - return ''; + return ""; } const filterQuery = getFilterQuery(filters, { isCohort: true }); @@ -148,7 +141,7 @@ function getDateQuery(filters: Record) { } } - return ''; + return ""; } function getQueryParams(filters: Record) { @@ -165,9 +158,7 @@ function getQueryParams(filters: Record) { } function parseFilters(filters: Record, options?: QueryOptions) { - const cohortFilters = Object.fromEntries( - Object.entries(filters).filter(([key]) => key.startsWith('cohort_')), - ); + const cohortFilters = Object.fromEntries(Object.entries(filters).filter(([key]) => key.startsWith("cohort_"))); return { filterQuery: getFilterQuery(filters, options), @@ -177,38 +168,22 @@ function parseFilters(filters: Record, options?: QueryOptions) { }; } -async function pagedRawQuery( - query: string, - queryParams: Record, - filters: QueryFilters, - name?: string, -) { +async function pagedRawQuery(query: string, queryParams: Record, filters: QueryFilters, name?: string) { const { page = 1, pageSize, orderBy, sortDescending = false, search } = filters; const size = +pageSize || DEFAULT_PAGE_SIZE; const offset = +size * (+page - 1); - const direction = sortDescending ? 'desc' : 'asc'; + const direction = sortDescending ? "desc" : "asc"; - const statements = [ - orderBy && `order by ${orderBy} ${direction}`, - +size > 0 && `limit ${+size} offset ${+offset}`, - ] - .filter(n => n) - .join('\n'); + const statements = [orderBy && `order by ${orderBy} ${direction}`, +size > 0 && `limit ${+size} offset ${+offset}`].filter((n) => n).join("\n"); - const count = await rawQuery(`select count(*) as num from (${query}) t`, queryParams).then( - res => res[0].num, - ); + const count = await rawQuery(`select count(*) as num from (${query}) t`, queryParams).then((res) => res[0].num); const data = await rawQuery(`${query}${statements}`, queryParams, name); return { data, count, page: +page, pageSize: size, orderBy, search }; } -async function rawQuery( - query: string, - params: Record = {}, - name?: string, -): Promise { +async function rawQuery(query: string, params: Record = {}, name?: string): Promise { if (process.env.LOG_QUERY) { log({ query, params, name }); } @@ -218,9 +193,9 @@ async function rawQuery( const resultSet = await clickhouse.query({ query: query, query_params: params, - format: 'JSONEachRow', + format: "JSONEachRow", clickhouse_settings: { - date_time_output_format: 'iso', + date_time_output_format: "iso", output_format_json_quote_64bit_integers: 0, }, }); @@ -231,7 +206,7 @@ async function rawQuery( async function insert(table: string, values: any[]) { await connect(); - return clickhouse.insert({ table, values, format: 'JSONEachRow' }); + return clickhouse.insert({ table, values, format: "JSONEachRow" }); } async function findUnique(data: any[]) { diff --git a/src/lib/constants.ts b/src/lib/constants.ts index e5090c3c0..11fec5bf5 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -1,89 +1,69 @@ export const CURRENT_VERSION = process.env.currentVersion; -export const AUTH_TOKEN = 'umami.auth'; -export const LOCALE_CONFIG = 'umami.locale'; -export const TIMEZONE_CONFIG = 'umami.timezone'; -export const DATE_RANGE_CONFIG = 'umami.date-range'; -export const THEME_CONFIG = 'umami.theme'; -export const DASHBOARD_CONFIG = 'umami.dashboard'; -export const LAST_TEAM_CONFIG = 'umami.last-team'; -export const VERSION_CHECK = 'umami.version-check'; -export const SHARE_TOKEN_HEADER = 'x-umami-share-token'; -export const HOMEPAGE_URL = 'https://umami.is'; -export const DOCS_URL = 'https://umami.is/docs'; -export const REPO_URL = 'https://github.com/umami-software/umami'; -export const UPDATES_URL = 'https://api.umami.is/v1/updates'; -export const TELEMETRY_PIXEL = 'https://i.umami.is/a.png'; -export const FAVICON_URL = 'https://icons.duckduckgo.com/ip3/{{domain}}.ico'; +export const AUTH_TOKEN = "syncfuse.auth"; +export const LOCALE_CONFIG = "syncfuse.locale"; +export const TIMEZONE_CONFIG = "syncfuse.timezone"; +export const DATE_RANGE_CONFIG = "syncfuse.date-range"; +export const THEME_CONFIG = "syncfuse.theme"; +export const DASHBOARD_CONFIG = "syncfuse.dashboard"; +export const LAST_TEAM_CONFIG = "syncfuse.last-team"; +export const VERSION_CHECK = "syncfuse.version-check"; +export const SHARE_TOKEN_HEADER = "x-syncfuse-share-token"; +export const HOMEPAGE_URL = "https://umami.is"; +export const DOCS_URL = "https://umami.is/docs"; +export const REPO_URL = "https://github.com/umami-software/umami"; +export const UPDATES_URL = "https://api.umami.is/v1/updates"; +export const TELEMETRY_PIXEL = "https://i.umami.is/a.png"; +export const FAVICON_URL = "https://icons.duckduckgo.com/ip3/{{domain}}.ico"; export const LINKS_URL = `${globalThis?.location?.origin}/q`; export const PIXELS_URL = `${globalThis?.location?.origin}/p`; -export const DEFAULT_LOCALE = 'en-US'; -export const DEFAULT_THEME = 'light'; +export const DEFAULT_LOCALE = "en-US"; +export const DEFAULT_THEME = "light"; export const DEFAULT_ANIMATION_DURATION = 300; -export const DEFAULT_DATE_RANGE_VALUE = '24hour'; +export const DEFAULT_DATE_RANGE_VALUE = "24hour"; export const DEFAULT_WEBSITE_LIMIT = 10; -export const DEFAULT_RESET_DATE = '2000-01-01'; +export const DEFAULT_RESET_DATE = "2000-01-01"; export const DEFAULT_PAGE_SIZE = 20; -export const DEFAULT_DATE_COMPARE = 'prev'; +export const DEFAULT_DATE_COMPARE = "prev"; export const REALTIME_RANGE = 30; export const REALTIME_INTERVAL = 10000; -export const UNIT_TYPES = ['year', 'month', 'hour', 'day', 'minute']; +export const UNIT_TYPES = ["year", "month", "hour", "day", "minute"]; -export const EVENT_COLUMNS = [ - 'path', - 'entry', - 'exit', - 'referrer', - 'domain', - 'title', - 'query', - 'event', - 'tag', - 'hostname', -]; +export const EVENT_COLUMNS = ["path", "entry", "exit", "referrer", "domain", "title", "query", "event", "tag", "hostname"]; -export const SESSION_COLUMNS = [ - 'browser', - 'os', - 'device', - 'screen', - 'language', - 'country', - 'city', - 'region', -]; +export const SESSION_COLUMNS = ["browser", "os", "device", "screen", "language", "country", "city", "region"]; export const SEGMENT_TYPES = { - segment: 'segment', - cohort: 'cohort', + segment: "segment", + cohort: "cohort", }; export const FILTER_COLUMNS = { - path: 'url_path', - entry: 'url_path', - exit: 'url_path', - referrer: 'referrer_domain', - domain: 'referrer_domain', - hostname: 'hostname', - title: 'page_title', - query: 'url_query', - os: 'os', - browser: 'browser', - device: 'device', - country: 'country', - region: 'region', - city: 'city', - language: 'language', - event: 'event_name', - tag: 'tag', - eventType: 'event_type', + path: "url_path", + entry: "url_path", + exit: "url_path", + referrer: "referrer_domain", + domain: "referrer_domain", + hostname: "hostname", + title: "page_title", + query: "url_query", + os: "os", + browser: "browser", + device: "device", + country: "country", + region: "region", + city: "city", + language: "language", + event: "event_name", + tag: "tag", + eventType: "event_type", }; export const COLLECTION_TYPE = { - event: 'event', - identify: 'identify', + event: "event", + identify: "identify", } as const; export const EVENT_TYPE = { @@ -102,581 +82,480 @@ export const DATA_TYPE = { } as const; export const OPERATORS = { - equals: 'eq', - notEquals: 'neq', - set: 's', - notSet: 'ns', - contains: 'c', - doesNotContain: 'dnc', - true: 't', - false: 'f', - greaterThan: 'gt', - lessThan: 'lt', - greaterThanEquals: 'gte', - lessThanEquals: 'lte', - before: 'bf', - after: 'af', + equals: "eq", + notEquals: "neq", + set: "s", + notSet: "ns", + contains: "c", + doesNotContain: "dnc", + true: "t", + false: "f", + greaterThan: "gt", + lessThan: "lt", + greaterThanEquals: "gte", + lessThanEquals: "lte", + before: "bf", + after: "af", } as const; export const DATA_TYPES = { - [DATA_TYPE.string]: 'string', - [DATA_TYPE.number]: 'number', - [DATA_TYPE.boolean]: 'boolean', - [DATA_TYPE.date]: 'date', - [DATA_TYPE.array]: 'array', + [DATA_TYPE.string]: "string", + [DATA_TYPE.number]: "number", + [DATA_TYPE.boolean]: "boolean", + [DATA_TYPE.date]: "date", + [DATA_TYPE.array]: "array", } as const; export const ROLES = { - admin: 'admin', - user: 'user', - viewOnly: 'view-only', - teamOwner: 'team-owner', - teamManager: 'team-manager', - teamMember: 'team-member', - teamViewOnly: 'team-view-only', + admin: "admin", + user: "user", + viewOnly: "view-only", + teamOwner: "team-owner", + teamManager: "team-manager", + teamMember: "team-member", + teamViewOnly: "team-view-only", } as const; export const PERMISSIONS = { - all: 'all', - websiteCreate: 'website:create', - websiteUpdate: 'website:update', - websiteDelete: 'website:delete', - websiteTransferToTeam: 'website:transfer-to-team', - websiteTransferToUser: 'website:transfer-to-user', - teamCreate: 'team:create', - teamUpdate: 'team:update', - teamDelete: 'team:delete', + all: "all", + websiteCreate: "website:create", + websiteUpdate: "website:update", + websiteDelete: "website:delete", + websiteTransferToTeam: "website:transfer-to-team", + websiteTransferToUser: "website:transfer-to-user", + teamCreate: "team:create", + teamUpdate: "team:update", + teamDelete: "team:delete", } as const; export const ROLE_PERMISSIONS = { [ROLES.admin]: [PERMISSIONS.all], - [ROLES.user]: [ - PERMISSIONS.websiteCreate, - PERMISSIONS.websiteUpdate, - PERMISSIONS.websiteDelete, - PERMISSIONS.teamCreate, - ], + [ROLES.user]: [PERMISSIONS.websiteCreate, PERMISSIONS.websiteUpdate, PERMISSIONS.websiteDelete, PERMISSIONS.teamCreate], [ROLES.viewOnly]: [], - [ROLES.teamOwner]: [ - PERMISSIONS.teamUpdate, - PERMISSIONS.teamDelete, - PERMISSIONS.websiteCreate, - PERMISSIONS.websiteUpdate, - PERMISSIONS.websiteDelete, - PERMISSIONS.websiteTransferToTeam, - PERMISSIONS.websiteTransferToUser, - ], - [ROLES.teamManager]: [ - PERMISSIONS.teamUpdate, - PERMISSIONS.websiteCreate, - PERMISSIONS.websiteUpdate, - PERMISSIONS.websiteDelete, - PERMISSIONS.websiteTransferToTeam, - ], - [ROLES.teamMember]: [ - PERMISSIONS.websiteCreate, - PERMISSIONS.websiteUpdate, - PERMISSIONS.websiteDelete, - ], + [ROLES.teamOwner]: [PERMISSIONS.teamUpdate, PERMISSIONS.teamDelete, PERMISSIONS.websiteCreate, PERMISSIONS.websiteUpdate, PERMISSIONS.websiteDelete, PERMISSIONS.websiteTransferToTeam, PERMISSIONS.websiteTransferToUser], + [ROLES.teamManager]: [PERMISSIONS.teamUpdate, PERMISSIONS.websiteCreate, PERMISSIONS.websiteUpdate, PERMISSIONS.websiteDelete, PERMISSIONS.websiteTransferToTeam], + [ROLES.teamMember]: [PERMISSIONS.websiteCreate, PERMISSIONS.websiteUpdate, PERMISSIONS.websiteDelete], [ROLES.teamViewOnly]: [], } as const; export const THEME_COLORS = { light: { - primary: '#2680eb', - text: '#838383', - line: '#d9d9d9', - fill: '#f9f9f9', + primary: "#2680eb", + text: "#838383", + line: "#d9d9d9", + fill: "#f9f9f9", }, dark: { - primary: '#2680eb', - text: '#7b7b7b', - line: '#3a3a3a', - fill: '#191919', + primary: "#2680eb", + text: "#7b7b7b", + line: "#3a3a3a", + fill: "#191919", }, } as const; -export const CHART_COLORS = [ - '#2680eb', - '#9256d9', - '#44b556', - '#e68619', - '#e34850', - '#f7bd12', - '#01bad7', - '#6734bc', - '#89c541', - '#ffc301', - '#ec1562', - '#ffec16', -]; +export const CHART_COLORS = ["#2680eb", "#9256d9", "#44b556", "#e68619", "#e34850", "#f7bd12", "#01bad7", "#6734bc", "#89c541", "#ffc301", "#ec1562", "#ffec16"]; -export const DOMAIN_REGEX = - /^(localhost(:[1-9]\d{0,4})?|((?=[a-z0-9-_]{1,63}\.)(xn--)?[a-z0-9-_]+(-[a-z0-9-_]+)*\.)+(xn--)?[a-z0-9-_]{2,63})$/; +export const DOMAIN_REGEX = /^(localhost(:[1-9]\d{0,4})?|((?=[a-z0-9-_]{1,63}\.)(xn--)?[a-z0-9-_]+(-[a-z0-9-_]+)*\.)+(xn--)?[a-z0-9-_]{2,63})$/; export const SHARE_ID_REGEX = /^[a-zA-Z0-9]{8,50}$/; -export const DATETIME_REGEX = - /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{3}(Z|\+[0-9]{2}:[0-9]{2})?)?$/; +export const DATETIME_REGEX = /^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]{3}(Z|\+[0-9]{2}:[0-9]{2})?)?$/; export const URL_LENGTH = 500; export const PAGE_TITLE_LENGTH = 500; export const EVENT_NAME_LENGTH = 50; -export const UTM_PARAMS = ['utm_campaign', 'utm_content', 'utm_medium', 'utm_source', 'utm_term']; +export const UTM_PARAMS = ["utm_campaign", "utm_content", "utm_medium", "utm_source", "utm_term"]; export const OS_NAMES = { - 'Android OS': 'Android', - 'Chrome OS': 'ChromeOS', - 'Mac OS': 'macOS', - 'Sun OS': 'SunOS', - 'Windows 10': 'Windows 10/11', + "Android OS": "Android", + "Chrome OS": "ChromeOS", + "Mac OS": "macOS", + "Sun OS": "SunOS", + "Windows 10": "Windows 10/11", } as const; export const BROWSERS = { - android: 'Android', - aol: 'AOL', - bb10: 'BlackBerry 10', - beaker: 'Beaker', - chrome: 'Chrome', - 'chromium-webview': 'Chrome (webview)', - crios: 'Chrome (iOS)', - curl: 'Curl', - edge: 'Edge', - 'edge-chromium': 'Edge (Chromium)', - 'edge-ios': 'Edge (iOS)', - facebook: 'Facebook', - firefox: 'Firefox', - fxios: 'Firefox (iOS)', - ie: 'IE', - instagram: 'Instagram', - ios: 'iOS', - 'ios-webview': 'iOS (webview)', - kakaotalk: 'KakaoTalk', - miui: 'MIUI', - opera: 'Opera', - 'opera-mini': 'Opera Mini', - phantomjs: 'PhantomJS', - safari: 'Safari', - samsung: 'Samsung', - searchbot: 'Searchbot', - silk: 'Silk', - yandexbrowser: 'Yandex', + android: "Android", + aol: "AOL", + bb10: "BlackBerry 10", + beaker: "Beaker", + chrome: "Chrome", + "chromium-webview": "Chrome (webview)", + crios: "Chrome (iOS)", + curl: "Curl", + edge: "Edge", + "edge-chromium": "Edge (Chromium)", + "edge-ios": "Edge (iOS)", + facebook: "Facebook", + firefox: "Firefox", + fxios: "Firefox (iOS)", + ie: "IE", + instagram: "Instagram", + ios: "iOS", + "ios-webview": "iOS (webview)", + kakaotalk: "KakaoTalk", + miui: "MIUI", + opera: "Opera", + "opera-mini": "Opera Mini", + phantomjs: "PhantomJS", + safari: "Safari", + samsung: "Samsung", + searchbot: "Searchbot", + silk: "Silk", + yandexbrowser: "Yandex", } as const; -export const SOCIAL_DOMAINS = [ - 'bsky.app', - 'facebook.com', - 'fb.com', - 'ig.com', - 'instagram.com', - 'linkedin.', - 'news.ycombinator.com', - 'pinterest.', - 'reddit.', - 'snapchat.', - 't.co', - 'threads.net', - 'tiktok.', - 'twitter.com', - 'x.com', -]; +export const SOCIAL_DOMAINS = ["bsky.app", "facebook.com", "fb.com", "ig.com", "instagram.com", "linkedin.", "news.ycombinator.com", "pinterest.", "reddit.", "snapchat.", "t.co", "threads.net", "tiktok.", "twitter.com", "x.com"]; -export const SEARCH_DOMAINS = [ - 'baidu.com', - 'bing.com', - 'chatgpt.com', - 'duckduckgo.com', - 'ecosia.org', - 'google.', - 'msn.com', - 'perplexity.ai', - 'search.brave.com', - 'yandex.', -]; +export const SEARCH_DOMAINS = ["baidu.com", "bing.com", "chatgpt.com", "duckduckgo.com", "ecosia.org", "google.", "msn.com", "perplexity.ai", "search.brave.com", "yandex."]; -export const SHOPPING_DOMAINS = [ - 'alibaba.com', - 'aliexpress.com', - 'amazon.', - 'bestbuy.com', - 'ebay.com', - 'etsy.com', - 'newegg.com', - 'target.com', - 'walmart.com', -]; +export const SHOPPING_DOMAINS = ["alibaba.com", "aliexpress.com", "amazon.", "bestbuy.com", "ebay.com", "etsy.com", "newegg.com", "target.com", "walmart.com"]; -export const EMAIL_DOMAINS = [ - 'gmail.', - 'hotmail.', - 'mail.yahoo.', - 'outlook.', - 'proton.me', - 'protonmail.', -]; +export const EMAIL_DOMAINS = ["gmail.", "hotmail.", "mail.yahoo.", "outlook.", "proton.me", "protonmail."]; -export const VIDEO_DOMAINS = ['twitch.', 'youtube.']; +export const VIDEO_DOMAINS = ["twitch.", "youtube."]; -export const PAID_AD_PARAMS = [ - 'ad_id=', - 'aid=', - 'dclid=', - 'epik=', - 'fbclid=', - 'gclid=', - 'li_fat_id=', - 'msclkid=', - 'ob_click_id=', - 'pc_id=', - 'rdt_cid=', - 'scid=', - 'ttclid=', - 'twclid=', - 'utm_medium=cpc', - 'utm_medium=paid', - 'utm_medium=paid_social', - 'utm_source=google', -]; +export const PAID_AD_PARAMS = ["ad_id=", "aid=", "dclid=", "epik=", "fbclid=", "gclid=", "li_fat_id=", "msclkid=", "ob_click_id=", "pc_id=", "rdt_cid=", "scid=", "ttclid=", "twclid=", "utm_medium=cpc", "utm_medium=paid", "utm_medium=paid_social", "utm_source=google"]; export const GROUPED_DOMAINS = [ - { name: 'Baidu', domain: 'baidu.com', match: 'baidu.' }, - { name: 'Bing', domain: 'bing.com', match: 'bing.' }, - { name: 'Brave', domain: 'brave.com', match: 'brave.' }, - { name: 'ChatGPT', domain: 'chatgpt.com', match: 'chatgpt.' }, - { name: 'DuckDuckGo', domain: 'duckduckgo.com', match: 'duckduckgo.' }, - { name: 'Facebook', domain: 'facebook.com', match: 'facebook.' }, - { name: 'GitHub', domain: 'github.com', match: 'github.' }, - { name: 'Google', domain: 'google.com', match: 'google.' }, - { name: 'Hacker News', domain: 'news.ycombinator.com', match: 'news.ycombinator.com' }, - { name: 'Instagram', domain: 'instagram.com', match: ['instagram.', 'ig.com'] }, - { name: 'LinkedIn', domain: 'linkedin.com', match: 'linkedin.' }, - { name: 'Pinterest', domain: 'pinterest.com', match: 'pinterest.' }, - { name: 'Reddit', domain: 'reddit.com', match: 'reddit.' }, - { name: 'Snapchat', domain: 'snapchat.com', match: 'snapchat.' }, - { name: 'Twitter', domain: 'twitter.com', match: ['twitter.', 't.co', 'x.com'] }, - { name: 'Yahoo', domain: 'yahoo.com', match: 'yahoo.' }, - { name: 'Yandex', domain: 'yandex.ru', match: 'yandex.' }, + { name: "Baidu", domain: "baidu.com", match: "baidu." }, + { name: "Bing", domain: "bing.com", match: "bing." }, + { name: "Brave", domain: "brave.com", match: "brave." }, + { name: "ChatGPT", domain: "chatgpt.com", match: "chatgpt." }, + { name: "DuckDuckGo", domain: "duckduckgo.com", match: "duckduckgo." }, + { name: "Facebook", domain: "facebook.com", match: "facebook." }, + { name: "GitHub", domain: "github.com", match: "github." }, + { name: "Google", domain: "google.com", match: "google." }, + { name: "Hacker News", domain: "news.ycombinator.com", match: "news.ycombinator.com" }, + { name: "Instagram", domain: "instagram.com", match: ["instagram.", "ig.com"] }, + { name: "LinkedIn", domain: "linkedin.com", match: "linkedin." }, + { name: "Pinterest", domain: "pinterest.com", match: "pinterest." }, + { name: "Reddit", domain: "reddit.com", match: "reddit." }, + { name: "Snapchat", domain: "snapchat.com", match: "snapchat." }, + { name: "Twitter", domain: "twitter.com", match: ["twitter.", "t.co", "x.com"] }, + { name: "Yahoo", domain: "yahoo.com", match: "yahoo." }, + { name: "Yandex", domain: "yandex.ru", match: "yandex." }, ]; -export const MAP_FILE = '/datamaps.world.json'; +export const MAP_FILE = "/datamaps.world.json"; export const ISO_COUNTRIES = { - ABW: 'AW', - AFG: 'AF', - AGO: 'AO', - AIA: 'AI', - ALA: 'AX', - ALB: 'AL', - AND: 'AD', - ANT: 'AN', - ARE: 'AE', - ARG: 'AR', - ARM: 'AM', - ASM: 'AS', - ATF: 'TF', - ATG: 'AG', - AUS: 'AU', - AUT: 'AT', - AZE: 'AZ', - BDI: 'BI', - BEL: 'BE', - BEN: 'BJ', - BFA: 'BF', - BGD: 'BD', - BGR: 'BG', - BHR: 'BH', - BHS: 'BS', - BIH: 'BA', - BLR: 'BY', - BLZ: 'BZ', - BLM: 'BL', - BMU: 'BM', - BOL: 'BO', - BRA: 'BR', - BRB: 'BB', - BRN: 'BN', - BTN: 'BT', - BVT: 'BV', - BWA: 'BW', - CAF: 'CF', - CAN: 'CA', - CCK: 'CC', - CHE: 'CH', - CHL: 'CL', - CHN: 'CN', - CIV: 'CI', - CMR: 'CM', - COD: 'CD', - COG: 'CG', - COK: 'CK', - COL: 'CO', - COM: 'KM', - CPV: 'CV', - CRI: 'CR', - CUB: 'CU', - CXR: 'CX', - CYM: 'KY', - CYP: 'CY', - CZE: 'CZ', - DEU: 'DE', - DJI: 'DJ', - DMA: 'DM', - DNK: 'DK', - DOM: 'DO', - DZA: 'DZ', - ECU: 'EC', - EGY: 'EG', - ERI: 'ER', - ESH: 'EH', - ESP: 'ES', - EST: 'EE', - ETH: 'ET', - FIN: 'FI', - FJI: 'FJ', - FLK: 'FK', - FRA: 'FR', - FRO: 'FO', - FSM: 'FM', - GAB: 'GA', - GBR: 'GB', - GEO: 'GE', - GGY: 'GG', - GHA: 'GH', - GIB: 'GI', - GIN: 'GN', - GLP: 'GP', - GMB: 'GM', - GNB: 'GW', - GNQ: 'GQ', - GRC: 'GR', - GRD: 'GD', - GRL: 'GL', - GTM: 'GT', - GUF: 'GF', - GUM: 'GU', - GUY: 'GY', - HKG: 'HK', - HMD: 'HM', - HND: 'HN', - HRV: 'HR', - HTI: 'HT', - HUN: 'HU', - IDN: 'ID', - IMN: 'IM', - IND: 'IN', - IOT: 'IO', - IRL: 'IE', - IRN: 'IR', - IRQ: 'IQ', - ISL: 'IS', - ISR: 'IL', - ITA: 'IT', - JAM: 'JM', - JEY: 'JE', - JOR: 'JO', - JPN: 'JP', - KAZ: 'KZ', - KEN: 'KE', - KGZ: 'KG', - KHM: 'KH', - KIR: 'KI', - KNA: 'KN', - KOR: 'KR', - KWT: 'KW', - LAO: 'LA', - LBN: 'LB', - LBR: 'LR', - LBY: 'LY', - LCA: 'LC', - LIE: 'LI', - LKA: 'LK', - LSO: 'LS', - LTU: 'LT', - LUX: 'LU', - LVA: 'LV', - MAF: 'MF', - MAR: 'MA', - MCO: 'MC', - MDA: 'MD', - MDG: 'MG', - MDV: 'MV', - MEX: 'MX', - MHL: 'MH', - MKD: 'MK', - MLI: 'ML', - MLT: 'MT', - MMR: 'MM', - MNE: 'ME', - MNG: 'MN', - MNP: 'MP', - MOZ: 'MZ', - MRT: 'MR', - MSR: 'MS', - MTQ: 'MQ', - MUS: 'MU', - MWI: 'MW', - MYS: 'MY', - MYT: 'YT', - NAM: 'NA', - NCL: 'NC', - NER: 'NE', - NFK: 'NF', - NGA: 'NG', - NIC: 'NI', - NIU: 'NU', - NLD: 'NL', - NOR: 'NO', - NPL: 'NP', - NRU: 'NR', - NZL: 'NZ', - OMN: 'OM', - PAK: 'PK', - PAN: 'PA', - PCN: 'PN', - PER: 'PE', - PHL: 'PH', - PLW: 'PW', - PNG: 'PG', - POL: 'PL', - PRI: 'PR', - PRK: 'KP', - PRT: 'PT', - PRY: 'PY', - PSE: 'PS', - PYF: 'PF', - QAT: 'QA', - REU: 'RE', - ROU: 'RO', - RUS: 'RU', - RWA: 'RW', - SAU: 'SA', - SDN: 'SD', - SEN: 'SN', - SGP: 'SG', - SGS: 'GS', - SHN: 'SH', - SJM: 'SJ', - SLB: 'SB', - SLE: 'SL', - SLV: 'SV', - SMR: 'SM', - SOM: 'SO', - SPM: 'PM', - SRB: 'RS', - SUR: 'SR', - STP: 'ST', - SVK: 'SK', - SVN: 'SI', - SWE: 'SE', - SWZ: 'SZ', - SYC: 'SC', - SYR: 'SY', - TCA: 'TC', - TCD: 'TD', - TGO: 'TG', - THA: 'TH', - TJK: 'TJ', - TKL: 'TK', - TKM: 'TM', - TLS: 'TL', - TON: 'TO', - TTO: 'TT', - TUN: 'TN', - TUR: 'TR', - TUV: 'TV', - TWN: 'TW', - TZA: 'TZ', - UGA: 'UG', - UKR: 'UA', - UMI: 'UM', - URY: 'UY', - USA: 'US', - UZB: 'UZ', - VAT: 'VA', - VCT: 'VC', - VEN: 'VE', - VGB: 'VG', - VIR: 'VI', - VNM: 'VN', - VUT: 'VU', - WLF: 'WF', - WSM: 'WS', - XKX: 'XK', - YEM: 'YE', - ZAF: 'ZA', - ZMB: 'ZM', - ZWE: 'ZW', + ABW: "AW", + AFG: "AF", + AGO: "AO", + AIA: "AI", + ALA: "AX", + ALB: "AL", + AND: "AD", + ANT: "AN", + ARE: "AE", + ARG: "AR", + ARM: "AM", + ASM: "AS", + ATF: "TF", + ATG: "AG", + AUS: "AU", + AUT: "AT", + AZE: "AZ", + BDI: "BI", + BEL: "BE", + BEN: "BJ", + BFA: "BF", + BGD: "BD", + BGR: "BG", + BHR: "BH", + BHS: "BS", + BIH: "BA", + BLR: "BY", + BLZ: "BZ", + BLM: "BL", + BMU: "BM", + BOL: "BO", + BRA: "BR", + BRB: "BB", + BRN: "BN", + BTN: "BT", + BVT: "BV", + BWA: "BW", + CAF: "CF", + CAN: "CA", + CCK: "CC", + CHE: "CH", + CHL: "CL", + CHN: "CN", + CIV: "CI", + CMR: "CM", + COD: "CD", + COG: "CG", + COK: "CK", + COL: "CO", + COM: "KM", + CPV: "CV", + CRI: "CR", + CUB: "CU", + CXR: "CX", + CYM: "KY", + CYP: "CY", + CZE: "CZ", + DEU: "DE", + DJI: "DJ", + DMA: "DM", + DNK: "DK", + DOM: "DO", + DZA: "DZ", + ECU: "EC", + EGY: "EG", + ERI: "ER", + ESH: "EH", + ESP: "ES", + EST: "EE", + ETH: "ET", + FIN: "FI", + FJI: "FJ", + FLK: "FK", + FRA: "FR", + FRO: "FO", + FSM: "FM", + GAB: "GA", + GBR: "GB", + GEO: "GE", + GGY: "GG", + GHA: "GH", + GIB: "GI", + GIN: "GN", + GLP: "GP", + GMB: "GM", + GNB: "GW", + GNQ: "GQ", + GRC: "GR", + GRD: "GD", + GRL: "GL", + GTM: "GT", + GUF: "GF", + GUM: "GU", + GUY: "GY", + HKG: "HK", + HMD: "HM", + HND: "HN", + HRV: "HR", + HTI: "HT", + HUN: "HU", + IDN: "ID", + IMN: "IM", + IND: "IN", + IOT: "IO", + IRL: "IE", + IRN: "IR", + IRQ: "IQ", + ISL: "IS", + ISR: "IL", + ITA: "IT", + JAM: "JM", + JEY: "JE", + JOR: "JO", + JPN: "JP", + KAZ: "KZ", + KEN: "KE", + KGZ: "KG", + KHM: "KH", + KIR: "KI", + KNA: "KN", + KOR: "KR", + KWT: "KW", + LAO: "LA", + LBN: "LB", + LBR: "LR", + LBY: "LY", + LCA: "LC", + LIE: "LI", + LKA: "LK", + LSO: "LS", + LTU: "LT", + LUX: "LU", + LVA: "LV", + MAF: "MF", + MAR: "MA", + MCO: "MC", + MDA: "MD", + MDG: "MG", + MDV: "MV", + MEX: "MX", + MHL: "MH", + MKD: "MK", + MLI: "ML", + MLT: "MT", + MMR: "MM", + MNE: "ME", + MNG: "MN", + MNP: "MP", + MOZ: "MZ", + MRT: "MR", + MSR: "MS", + MTQ: "MQ", + MUS: "MU", + MWI: "MW", + MYS: "MY", + MYT: "YT", + NAM: "NA", + NCL: "NC", + NER: "NE", + NFK: "NF", + NGA: "NG", + NIC: "NI", + NIU: "NU", + NLD: "NL", + NOR: "NO", + NPL: "NP", + NRU: "NR", + NZL: "NZ", + OMN: "OM", + PAK: "PK", + PAN: "PA", + PCN: "PN", + PER: "PE", + PHL: "PH", + PLW: "PW", + PNG: "PG", + POL: "PL", + PRI: "PR", + PRK: "KP", + PRT: "PT", + PRY: "PY", + PSE: "PS", + PYF: "PF", + QAT: "QA", + REU: "RE", + ROU: "RO", + RUS: "RU", + RWA: "RW", + SAU: "SA", + SDN: "SD", + SEN: "SN", + SGP: "SG", + SGS: "GS", + SHN: "SH", + SJM: "SJ", + SLB: "SB", + SLE: "SL", + SLV: "SV", + SMR: "SM", + SOM: "SO", + SPM: "PM", + SRB: "RS", + SUR: "SR", + STP: "ST", + SVK: "SK", + SVN: "SI", + SWE: "SE", + SWZ: "SZ", + SYC: "SC", + SYR: "SY", + TCA: "TC", + TCD: "TD", + TGO: "TG", + THA: "TH", + TJK: "TJ", + TKL: "TK", + TKM: "TM", + TLS: "TL", + TON: "TO", + TTO: "TT", + TUN: "TN", + TUR: "TR", + TUV: "TV", + TWN: "TW", + TZA: "TZ", + UGA: "UG", + UKR: "UA", + UMI: "UM", + URY: "UY", + USA: "US", + UZB: "UZ", + VAT: "VA", + VCT: "VC", + VEN: "VE", + VGB: "VG", + VIR: "VI", + VNM: "VN", + VUT: "VU", + WLF: "WF", + WSM: "WS", + XKX: "XK", + YEM: "YE", + ZAF: "ZA", + ZMB: "ZM", + ZWE: "ZW", }; export const CURRENCIES = [ - { id: 'USD', name: 'US Dollar' }, - { id: 'EUR', name: 'Euro' }, - { id: 'GBP', name: 'British Pound' }, - { id: 'JPY', name: 'Japanese Yen' }, - { id: 'CNY', name: 'Chinese Renminbi (Yuan)' }, - { id: 'CAD', name: 'Canadian Dollar' }, - { id: 'HKD', name: 'Hong Kong Dollar' }, - { id: 'AUD', name: 'Australian Dollar' }, - { id: 'SGD', name: 'Singapore Dollar' }, - { id: 'CHF', name: 'Swiss Franc' }, - { id: 'SEK', name: 'Swedish Krona' }, - { id: 'PLN', name: 'Polish Złoty' }, - { id: 'NOK', name: 'Norwegian Krone' }, - { id: 'DKK', name: 'Danish Krone' }, - { id: 'NZD', name: 'New Zealand Dollar' }, - { id: 'ZAR', name: 'South African Rand' }, - { id: 'MXN', name: 'Mexican Peso' }, - { id: 'THB', name: 'Thai Baht' }, - { id: 'HUF', name: 'Hungarian Forint' }, - { id: 'MYR', name: 'Malaysian Ringgit' }, - { id: 'INR', name: 'Indian Rupee' }, - { id: 'KRW', name: 'South Korean Won' }, - { id: 'BRL', name: 'Brazilian Real' }, - { id: 'TRY', name: 'Turkish Lira' }, - { id: 'CZK', name: 'Czech Koruna' }, - { id: 'ILS', name: 'Israeli New Shekel' }, - { id: 'RUB', name: 'Russian Ruble' }, - { id: 'AED', name: 'United Arab Emirates Dirham' }, - { id: 'IDR', name: 'Indonesian Rupiah' }, - { id: 'PHP', name: 'Philippine Peso' }, - { id: 'RON', name: 'Romanian Leu' }, - { id: 'COP', name: 'Colombian Peso' }, - { id: 'SAR', name: 'Saudi Riyal' }, - { id: 'ARS', name: 'Argentine Peso' }, - { id: 'VND', name: 'Vietnamese Dong' }, - { id: 'CLP', name: 'Chilean Peso' }, - { id: 'EGP', name: 'Egyptian Pound' }, - { id: 'KWD', name: 'Kuwaiti Dinar' }, - { id: 'PKR', name: 'Pakistani Rupee' }, - { id: 'QAR', name: 'Qatari Riyal' }, - { id: 'BHD', name: 'Bahraini Dinar' }, - { id: 'UAH', name: 'Ukrainian Hryvnia' }, - { id: 'PEN', name: 'Peruvian Sol' }, - { id: 'BDT', name: 'Bangladeshi Taka' }, - { id: 'MAD', name: 'Moroccan Dirham' }, - { id: 'KES', name: 'Kenyan Shilling' }, - { id: 'NGN', name: 'Nigerian Naira' }, - { id: 'TND', name: 'Tunisian Dinar' }, - { id: 'OMR', name: 'Omani Rial' }, - { id: 'GHS', name: 'Ghanaian Cedi' }, + { id: "USD", name: "US Dollar" }, + { id: "EUR", name: "Euro" }, + { id: "GBP", name: "British Pound" }, + { id: "JPY", name: "Japanese Yen" }, + { id: "CNY", name: "Chinese Renminbi (Yuan)" }, + { id: "CAD", name: "Canadian Dollar" }, + { id: "HKD", name: "Hong Kong Dollar" }, + { id: "AUD", name: "Australian Dollar" }, + { id: "SGD", name: "Singapore Dollar" }, + { id: "CHF", name: "Swiss Franc" }, + { id: "SEK", name: "Swedish Krona" }, + { id: "PLN", name: "Polish Złoty" }, + { id: "NOK", name: "Norwegian Krone" }, + { id: "DKK", name: "Danish Krone" }, + { id: "NZD", name: "New Zealand Dollar" }, + { id: "ZAR", name: "South African Rand" }, + { id: "MXN", name: "Mexican Peso" }, + { id: "THB", name: "Thai Baht" }, + { id: "HUF", name: "Hungarian Forint" }, + { id: "MYR", name: "Malaysian Ringgit" }, + { id: "INR", name: "Indian Rupee" }, + { id: "KRW", name: "South Korean Won" }, + { id: "BRL", name: "Brazilian Real" }, + { id: "TRY", name: "Turkish Lira" }, + { id: "CZK", name: "Czech Koruna" }, + { id: "ILS", name: "Israeli New Shekel" }, + { id: "RUB", name: "Russian Ruble" }, + { id: "AED", name: "United Arab Emirates Dirham" }, + { id: "IDR", name: "Indonesian Rupiah" }, + { id: "PHP", name: "Philippine Peso" }, + { id: "RON", name: "Romanian Leu" }, + { id: "COP", name: "Colombian Peso" }, + { id: "SAR", name: "Saudi Riyal" }, + { id: "ARS", name: "Argentine Peso" }, + { id: "VND", name: "Vietnamese Dong" }, + { id: "CLP", name: "Chilean Peso" }, + { id: "EGP", name: "Egyptian Pound" }, + { id: "KWD", name: "Kuwaiti Dinar" }, + { id: "PKR", name: "Pakistani Rupee" }, + { id: "QAR", name: "Qatari Riyal" }, + { id: "BHD", name: "Bahraini Dinar" }, + { id: "UAH", name: "Ukrainian Hryvnia" }, + { id: "PEN", name: "Peruvian Sol" }, + { id: "BDT", name: "Bangladeshi Taka" }, + { id: "MAD", name: "Moroccan Dirham" }, + { id: "KES", name: "Kenyan Shilling" }, + { id: "NGN", name: "Nigerian Naira" }, + { id: "TND", name: "Tunisian Dinar" }, + { id: "OMR", name: "Omani Rial" }, + { id: "GHS", name: "Ghanaian Cedi" }, ]; export const TIMEZONE_LEGACY: Record = { - 'Asia/Batavia': 'Asia/Jakarta', - 'Asia/Calcutta': 'Asia/Kolkata', - 'Asia/Chongqing': 'Asia/Shanghai', - 'Asia/Harbin': 'Asia/Shanghai', - 'Asia/Jayapura': 'Asia/Pontianak', - 'Asia/Katmandu': 'Asia/Kathmandu', - 'Asia/Macao': 'Asia/Macau', - 'Asia/Rangoon': 'Asia/Yangon', - 'Asia/Saigon': 'Asia/Ho_Chi_Minh', - 'Europe/Kiev': 'Europe/Kyiv', - 'Europe/Zaporozhye': 'Europe/Kyiv', - 'Etc/UTC': 'UTC', - 'US/Arizona': 'America/Phoenix', - 'US/Central': 'America/Chicago', - 'US/Eastern': 'America/New_York', - 'US/Mountain': 'America/Denver', - 'US/Pacific': 'America/Los_Angeles', - 'US/Samoa': 'Pacific/Pago_Pago', + "Asia/Batavia": "Asia/Jakarta", + "Asia/Calcutta": "Asia/Kolkata", + "Asia/Chongqing": "Asia/Shanghai", + "Asia/Harbin": "Asia/Shanghai", + "Asia/Jayapura": "Asia/Pontianak", + "Asia/Katmandu": "Asia/Kathmandu", + "Asia/Macao": "Asia/Macau", + "Asia/Rangoon": "Asia/Yangon", + "Asia/Saigon": "Asia/Ho_Chi_Minh", + "Europe/Kiev": "Europe/Kyiv", + "Europe/Zaporozhye": "Europe/Kyiv", + "Etc/UTC": "UTC", + "US/Arizona": "America/Phoenix", + "US/Central": "America/Chicago", + "US/Eastern": "America/New_York", + "US/Mountain": "America/Denver", + "US/Pacific": "America/Los_Angeles", + "US/Samoa": "Pacific/Pago_Pago", }; diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index 64cb870fd..e9eab323b 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -1,30 +1,30 @@ -import { PrismaPg } from '@prisma/adapter-pg'; -import { readReplicas } from '@prisma/extension-read-replicas'; -import debug from 'debug'; -import { PrismaClient } from '@/generated/prisma/client'; -import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS, SESSION_COLUMNS } from './constants'; -import { filtersObjectToArray } from './params'; -import type { Operator, QueryFilters, QueryOptions } from './types'; +import { PrismaPg } from "@prisma/adapter-pg"; +import { readReplicas } from "@prisma/extension-read-replicas"; +import debug from "debug"; +import { PrismaClient } from "@/generated/prisma/client"; +import { DEFAULT_PAGE_SIZE, FILTER_COLUMNS, OPERATORS, SESSION_COLUMNS } from "./constants"; +import { filtersObjectToArray } from "./params"; +import type { Operator, QueryFilters, QueryOptions } from "./types"; -const log = debug('umami:prisma'); +const log = debug("syncfuse:prisma"); -const PRISMA = 'prisma'; +const PRISMA = "prisma"; const PRISMA_LOG_OPTIONS = { log: [ { - emit: 'event' as const, - level: 'query' as const, + emit: "event" as const, + level: "query" as const, }, ], }; const DATE_FORMATS = { - minute: 'YYYY-MM-DD HH24:MI:00', - hour: 'YYYY-MM-DD HH24:00:00', - day: 'YYYY-MM-DD HH24:00:00', - month: 'YYYY-MM-01 HH24:00:00', - year: 'YYYY-01-01 HH24:00:00', + minute: "YYYY-MM-DD HH24:MI:00", + hour: "YYYY-MM-DD HH24:00:00", + day: "YYYY-MM-DD HH24:00:00", + month: "YYYY-MM-01 HH24:00:00", + year: "YYYY-01-01 HH24:00:00", }; const DATE_FORMATS_UTC = { @@ -48,7 +48,7 @@ function getCastColumnQuery(field: string, type: string): string { } function getDateSQL(field: string, unit: string, timezone?: string): string { - if (timezone && timezone !== 'utc') { + if (timezone && timezone !== "utc") { return `to_char(date_trunc('${unit}', ${field} at time zone '${timezone}'), '${DATE_FORMATS[unit]}')`; } @@ -67,12 +67,12 @@ function getTimestampDiffSQL(field1: string, field2: string): string { return `floor(extract(epoch from (${field2} - ${field1})))`; } -function getSearchSQL(column: string, param: string = 'search'): string { +function getSearchSQL(column: string, param: string = "search"): string { return `and ${column} ilike {{${param}}}`; } -function mapFilter(column: string, operator: string, name: string, type: string = '') { - const value = `{{${name}${type ? `::${type}` : ''}}}`; +function mapFilter(column: string, operator: string, name: string, type: string = "") { + const value = `{{${name}${type ? `::${type}` : ""}}}`; switch (operator) { case OPERATORS.equals: @@ -84,40 +84,35 @@ function mapFilter(column: string, operator: string, name: string, type: string case OPERATORS.doesNotContain: return `${column} not ilike ${value}`; default: - return ''; + return ""; } } function getFilterQuery(filters: Record, options: QueryOptions = {}): string { - const query = filtersObjectToArray(filters, options).reduce( - (arr, { name, column, operator, prefix = '' }) => { - const isCohort = options?.isCohort; + const query = filtersObjectToArray(filters, options).reduce((arr, { name, column, operator, prefix = "" }) => { + const isCohort = options?.isCohort; - if (isCohort) { - column = FILTER_COLUMNS[name.slice('cohort_'.length)]; + if (isCohort) { + column = FILTER_COLUMNS[name.slice("cohort_".length)]; + } + + if (column) { + arr.push(`and ${mapFilter(`${prefix}${column}`, operator, name)}`); + + if (name === "referrer") { + arr.push(`and (website_event.referrer_domain != website_event.hostname or website_event.referrer_domain is null)`); } + } - if (column) { - arr.push(`and ${mapFilter(`${prefix}${column}`, operator, name)}`); + return arr; + }, []); - if (name === 'referrer') { - arr.push( - `and (website_event.referrer_domain != website_event.hostname or website_event.referrer_domain is null)`, - ); - } - } - - return arr; - }, - [], - ); - - return query.join('\n'); + return query.join("\n"); } function getCohortQuery(filters: QueryFilters = {}) { if (!filters || Object.keys(filters).length === 0) { - return ''; + return ""; } const filterQuery = getFilterQuery(filters, { isCohort: true }); @@ -146,16 +141,14 @@ function getDateQuery(filters: Record) { } } - return ''; + return ""; } function getQueryParams(filters: Record) { return { ...filters, ...filtersObjectToArray(filters).reduce((obj, { name, operator, value }) => { - obj[name] = ([OPERATORS.contains, OPERATORS.doesNotContain] as Operator[]).includes(operator) - ? `%${value}%` - : value; + obj[name] = ([OPERATORS.contains, OPERATORS.doesNotContain] as Operator[]).includes(operator) ? `%${value}%` : value; return obj; }, {}), @@ -163,19 +156,12 @@ function getQueryParams(filters: Record) { } function parseFilters(filters: Record, options?: QueryOptions) { - const joinSession = Object.keys(filters).find(key => - ['referrer', ...SESSION_COLUMNS].includes(key), - ); + const joinSession = Object.keys(filters).find((key) => ["referrer", ...SESSION_COLUMNS].includes(key)); - const cohortFilters = Object.fromEntries( - Object.entries(filters).filter(([key]) => key.startsWith('cohort_')), - ); + const cohortFilters = Object.fromEntries(Object.entries(filters).filter(([key]) => key.startsWith("cohort_"))); return { - joinSessionQuery: - options?.joinSession || joinSession - ? `inner join session on website_event.session_id = session.session_id and website_event.website_id = session.website_id` - : '', + joinSessionQuery: options?.joinSession || joinSession ? `inner join session on website_event.session_id = session.session_id and website_event.website_id = session.website_id` : "", dateQuery: getDateQuery(filters), filterQuery: getFilterQuery(filters, options), queryParams: getQueryParams(filters), @@ -185,9 +171,9 @@ function parseFilters(filters: Record, options?: QueryOptions) { async function rawQuery(sql: string, data: Record, name?: string): Promise { if (process.env.LOG_QUERY) { - log('QUERY:\n', sql); - log('PARAMETERS:\n', data); - log('NAME:\n', name); + log("QUERY:\n", sql); + log("PARAMETERS:\n", data); + log("NAME:\n", name); } const params = []; const schema = getSchema(); @@ -203,10 +189,10 @@ async function rawQuery(sql: string, data: Record, name?: string): params.push(value); - return `$${params.length}${type ?? ''}`; + return `$${params.length}${type ?? ""}`; }); - if (process.env.DATABASE_REPLICA_URL && '$replica' in client) { + if (process.env.DATABASE_REPLICA_URL && "$replica" in client) { return client.$replica().$queryRawUnsafe(query, ...params); } @@ -224,7 +210,7 @@ async function pagedQuery(model: string, criteria: T, filters?: QueryFilters) ...(orderBy && { orderBy: [ { - [orderBy]: sortDescending ? 'desc' : 'asc', + [orderBy]: sortDescending ? "desc" : "asc", }, ], }), @@ -236,27 +222,15 @@ async function pagedQuery(model: string, criteria: T, filters?: QueryFilters) return { data, count, page: +page, pageSize: size, orderBy, search }; } -async function pagedRawQuery( - query: string, - queryParams: Record, - filters: QueryFilters, - name?: string, -) { +async function pagedRawQuery(query: string, queryParams: Record, filters: QueryFilters, name?: string) { const { page = 1, pageSize, orderBy, sortDescending = false } = filters; const size = +pageSize || DEFAULT_PAGE_SIZE; const offset = +size * (+page - 1); - const direction = sortDescending ? 'desc' : 'asc'; + const direction = sortDescending ? "desc" : "asc"; - const statements = [ - orderBy && `order by ${orderBy} ${direction}`, - +size > 0 && `limit ${+size} offset ${offset}`, - ] - .filter(n => n) - .join('\n'); + const statements = [orderBy && `order by ${orderBy} ${direction}`, +size > 0 && `limit ${+size} offset ${offset}`].filter((n) => n).join("\n"); - const count = await rawQuery(`select count(*) as num from (${query}) t`, queryParams).then( - res => res[0].num, - ); + const count = await rawQuery(`select count(*) as num from (${query}) t`, queryParams).then((res) => res[0].num); const data = await rawQuery(`${query}${statements}`, queryParams, name); @@ -271,16 +245,16 @@ function getSearchParameters(query: string, filters: Record[]) { return { [key]: - typeof value === 'string' + typeof value === "string" ? { [value]: query, - mode: 'insensitive', + mode: "insensitive", } : parseFilter(value), }; }; - const params = filters.map(filter => parseFilter(filter)); + const params = filters.map((filter) => parseFilter(filter)); return { AND: { @@ -296,7 +270,7 @@ function transaction(input: any, options?: any) { function getSchema() { const connectionUrl = new URL(process.env.DATABASE_URL); - return connectionUrl.searchParams.get('schema'); + return connectionUrl.searchParams.get("schema"); } function getClient() { @@ -309,16 +283,16 @@ function getClient() { const baseClient = new PrismaClient({ adapter: baseAdapter, - errorFormat: 'pretty', + errorFormat: "pretty", ...(logQuery ? PRISMA_LOG_OPTIONS : {}), }); if (logQuery) { - baseClient.$on('query', log); + baseClient.$on("query", log); } if (!replicaUrl) { - log('Prisma initialized'); + log("Prisma initialized"); globalThis[PRISMA] ??= baseClient; return baseClient; } @@ -327,12 +301,12 @@ function getClient() { const replicaClient = new PrismaClient({ adapter: replicaAdapter, - errorFormat: 'pretty', + errorFormat: "pretty", ...(logQuery ? PRISMA_LOG_OPTIONS : {}), }); if (logQuery) { - replicaClient.$on('query', log); + replicaClient.$on("query", log); } const extended = baseClient.$extends( @@ -341,7 +315,7 @@ function getClient() { }), ); - log('Prisma initialized (with replica)'); + log("Prisma initialized (with replica)"); globalThis[PRISMA] ??= extended; return extended; diff --git a/src/tracker/index.d.ts b/src/tracker/index.d.ts index 32fbee97f..364f359d9 100644 --- a/src/tracker/index.d.ts +++ b/src/tracker/index.d.ts @@ -35,7 +35,7 @@ export type TrackedProperties = { * Page title * * @description extracted from `document.querySelector('head > title')` - * @example 'umami' + * @example 'syncfuse' */ title: string; @@ -75,19 +75,17 @@ export type EventProperties = { */ name: string; data?: EventData; -} & WithRequired; -export type PageViewProperties = WithRequired; -export type CustomEventFunction = ( - props: PageViewProperties, -) => EventProperties | PageViewProperties; +} & WithRequired; +export type PageViewProperties = WithRequired; +export type CustomEventFunction = (props: PageViewProperties) => EventProperties | PageViewProperties; -export type UmamiTracker = { +export type SyncfuseTracker = { track: { /** * Track a page view * * @example ``` - * umami.track(); + * syncfuse.track(); * ``` */ (): Promise; @@ -98,7 +96,7 @@ export type UmamiTracker = { * NOTE: event names will be truncated past 50 characters * * @example ``` - * umami.track('signup-button'); + * syncfuse.track('signup-button'); * ``` */ (eventName: string): Promise; @@ -111,7 +109,7 @@ export type UmamiTracker = { * When tracking events, the default properties are included in the payload. This is equivalent to running: * * ```js - * umami.track(props => ({ + * syncfuse.track(props => ({ * ...props, * name: 'signup-button', * data: { @@ -122,7 +120,7 @@ export type UmamiTracker = { * ``` * * @example ``` - * umami.track('signup-button', { name: 'newsletter', id: 123 }); + * syncfuse.track('signup-button', { name: 'newsletter', id: 123 }); * ``` */ (eventName: string, obj: EventData): Promise; @@ -131,7 +129,7 @@ export type UmamiTracker = { * Tracks a page view with custom properties * * @example ``` - * umami.track({ website: 'e676c9b4-11e4-4ef1-a4d7-87001773e9f2', url: '/home', title: 'Home page' }); + * syncfuse.track({ website: 'e676c9b4-11e4-4ef1-a4d7-87001773e9f2', url: '/home', title: 'Home page' }); * ``` */ (properties: PageViewProperties): Promise; @@ -141,7 +139,7 @@ export type UmamiTracker = { * If you don't specify any `name` and/or `data`, it will be treated as a page view * * @example ``` - * umami.track((props) => ({ ...props, url: path })); + * syncfuse.track((props) => ({ ...props, url: path })); * ``` */ (eventFunction: CustomEventFunction): Promise; @@ -149,5 +147,5 @@ export type UmamiTracker = { }; export interface Window { - umami: UmamiTracker; + syncfuse: SyncfuseTracker; } diff --git a/src/tracker/index.js b/src/tracker/index.js index ad3648aca..bdd9f9d64 100644 --- a/src/tracker/index.js +++ b/src/tracker/index.js @@ -1,4 +1,4 @@ -(window => { +((window) => { const { screen: { width, height }, navigator: { language, doNotTrack: ndnt, msDoNotTrack: msdnt }, @@ -12,11 +12,11 @@ if (!currentScript) return; const { hostname, href, origin } = location; - const localStorage = href.startsWith('data:') ? undefined : window.localStorage; + const localStorage = href.startsWith("data:") ? undefined : window.localStorage; - const _data = 'data-'; - const _false = 'false'; - const _true = 'true'; + const _data = "data-"; + const _false = "false"; + const _true = "true"; const attr = currentScript.getAttribute.bind(currentScript); const website = attr(`${_data}website-id`); @@ -27,26 +27,25 @@ const dnt = attr(`${_data}do-not-track`) === _true; const excludeSearch = attr(`${_data}exclude-search`) === _true; const excludeHash = attr(`${_data}exclude-hash`) === _true; - const domain = attr(`${_data}domains`) || ''; - const credentials = attr(`${_data}fetch-credentials`) || 'omit'; + const domain = attr(`${_data}domains`) || ""; + const credentials = attr(`${_data}fetch-credentials`) || "omit"; - const domains = domain.split(',').map(n => n.trim()); - const host = - hostUrl || '__COLLECT_API_HOST__' || currentScript.src.split('/').slice(0, -1).join('/'); - const endpoint = `${host.replace(/\/$/, '')}__COLLECT_API_ENDPOINT__`; + const domains = domain.split(",").map((n) => n.trim()); + const host = hostUrl || "__COLLECT_API_HOST__" || currentScript.src.split("/").slice(0, -1).join("/"); + const endpoint = `${host.replace(/\/$/, "")}__COLLECT_API_ENDPOINT__`; const screen = `${width}x${height}`; - const eventRegex = /data-umami-event-([\w-_]+)/; - const eventNameAttribute = `${_data}umami-event`; + const eventRegex = /data-syncfuse-event-([\w-_]+)/; + const eventNameAttribute = `${_data}syncfuse-event`; const delayDuration = 300; /* Helper functions */ - const normalize = raw => { + const normalize = (raw) => { if (!raw) return raw; try { const u = new URL(raw, location.href); - if (excludeSearch) u.search = ''; - if (excludeHash) u.hash = ''; + if (excludeSearch) u.search = ""; + if (excludeHash) u.hash = ""; return u.toString(); } catch { return raw; @@ -67,7 +66,7 @@ const hasDoNotTrack = () => { const dnt = doNotTrack || ndnt || msdnt; - return dnt === 1 || dnt === '1' || dnt === 'yes'; + return dnt === 1 || dnt === "1" || dnt === "yes"; }; /* Event handlers */ @@ -92,17 +91,17 @@ }; }; - history.pushState = hook(history, 'pushState', handlePush); - history.replaceState = hook(history, 'replaceState', handlePush); + history.pushState = hook(history, "pushState", handlePush); + history.replaceState = hook(history, "replaceState", handlePush); }; const handleClicks = () => { - const trackElement = async el => { + const trackElement = async (el) => { const eventName = el.getAttribute(eventNameAttribute); if (eventName) { const eventData = {}; - el.getAttributeNames().forEach(name => { + el.getAttributeNames().forEach((name) => { const match = name.match(eventRegex); if (match) eventData[match[1]] = el.getAttribute(name); }); @@ -110,50 +109,40 @@ return track(eventName, eventData); } }; - const onClick = async e => { + const onClick = async (e) => { const el = e.target; - const parentElement = el.closest('a,button'); + const parentElement = el.closest("a,button"); if (!parentElement) return trackElement(el); const { href, target } = parentElement; if (!parentElement.getAttribute(eventNameAttribute)) return; - if (parentElement.tagName === 'BUTTON') { + if (parentElement.tagName === "BUTTON") { return trackElement(parentElement); } - if (parentElement.tagName === 'A' && href) { - const external = - target === '_blank' || - e.ctrlKey || - e.shiftKey || - e.metaKey || - (e.button && e.button === 1); + if (parentElement.tagName === "A" && href) { + const external = target === "_blank" || e.ctrlKey || e.shiftKey || e.metaKey || (e.button && e.button === 1); if (!external) e.preventDefault(); return trackElement(parentElement).then(() => { if (!external) { - (target === '_top' ? top.location : location).href = href; + (target === "_top" ? top.location : location).href = href; } }); } }; - document.addEventListener('click', onClick, true); + document.addEventListener("click", onClick, true); }; /* Tracking functions */ - const trackingDisabled = () => - disabled || - !website || - localStorage?.getItem('umami.disabled') || - (domain && !domains.includes(hostname)) || - (dnt && hasDoNotTrack()); + const trackingDisabled = () => disabled || !website || localStorage?.getItem("syncfuse.disabled") || (domain && !domains.includes(hostname)) || (dnt && hasDoNotTrack()); - const send = async (payload, type = 'event') => { + const send = async (payload, type = "event") => { if (trackingDisabled()) return; const callback = window[beforeSend]; - if (typeof callback === 'function') { + if (typeof callback === "function") { payload = await Promise.resolve(callback(type, payload)); } @@ -162,11 +151,11 @@ try { const res = await fetch(endpoint, { keepalive: true, - method: 'POST', + method: "POST", body: JSON.stringify({ type, payload }), headers: { - 'Content-Type': 'application/json', - ...(typeof cache !== 'undefined' && { 'x-umami-cache': cache }), + "Content-Type": "application/json", + ...(typeof cache !== "undefined" && { "x-syncfuse-cache": cache }), }, credentials, }); @@ -192,38 +181,38 @@ }; const track = (name, data) => { - if (typeof name === 'string') return send({ ...getPayload(), name, data }); - if (typeof name === 'object') return send({ ...name }); - if (typeof name === 'function') return send(name(getPayload())); + if (typeof name === "string") return send({ ...getPayload(), name, data }); + if (typeof name === "object") return send({ ...name }); + if (typeof name === "function") return send(name(getPayload())); return send(getPayload()); }; const identify = (id, data) => { - if (typeof id === 'string') { + if (typeof id === "string") { identity = id; } - cache = ''; + cache = ""; return send( { ...getPayload(), - data: typeof id === 'object' ? id : data, + data: typeof id === "object" ? id : data, }, - 'identify', + "identify", ); }; /* Start */ - if (!window.umami) { - window.umami = { + if (!window.syncfuse) { + window.syncfuse = { track, identify, }; } let currentUrl = normalize(href); - let currentRef = normalize(referrer.startsWith(origin) ? '' : referrer); + let currentRef = normalize(referrer.startsWith(origin) ? "" : referrer); let initialized = false; let disabled = false; @@ -231,10 +220,10 @@ let identity; if (autoTrack && !trackingDisabled()) { - if (document.readyState === 'complete') { + if (document.readyState === "complete") { init(); } else { - document.addEventListener('readystatechange', init, true); + document.addEventListener("readystatechange", init, true); } } })(window);