Merge pull request #3242 from umami-software/analytics

v2.16
This commit is contained in:
Mike Cao 2025-02-20 20:44:41 -08:00 committed by GitHub
commit b6e543801c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
469 changed files with 7191 additions and 7464 deletions

View file

@ -13,13 +13,6 @@
"ecmaVersion": 11, "ecmaVersion": 11,
"sourceType": "module" "sourceType": "module"
}, },
"settings": {
"import/resolver": {
"node": {
"moduleDirectory": ["node_modules", "src/"]
}
}
},
"extends": [ "extends": [
"plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended",
"eslint:recommended", "eslint:recommended",

View file

@ -1,5 +1,5 @@
# Install dependencies only when needed # Install dependencies only when needed
FROM node:18-alpine AS deps FROM node:22-alpine AS deps
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
RUN apk add --no-cache libc6-compat RUN apk add --no-cache libc6-compat
WORKDIR /app WORKDIR /app
@ -9,7 +9,7 @@ RUN yarn config set network-timeout 300000
RUN yarn install --frozen-lockfile RUN yarn install --frozen-lockfile
# Rebuild the source code only when needed # Rebuild the source code only when needed
FROM node:18-alpine AS builder FROM node:22-alpine AS builder
WORKDIR /app WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
@ -26,18 +26,21 @@ ENV NEXT_TELEMETRY_DISABLED 1
RUN yarn build-docker RUN yarn build-docker
# Production image, copy all the files and run next # Production image, copy all the files and run next
FROM node:18-alpine AS runner FROM node:22-alpine AS runner
WORKDIR /app WORKDIR /app
ARG NODE_OPTIONS
ENV NODE_ENV production ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1 ENV NEXT_TELEMETRY_DISABLED 1
ENV NODE_OPTIONS $NODE_OPTIONS
RUN addgroup --system --gid 1001 nodejs RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs RUN adduser --system --uid 1001 nextjs
RUN set -x \ RUN set -x \
&& apk add --no-cache curl openssl \ && apk add --no-cache curl \
&& yarn add npm-run-all dotenv semver prisma@5.17.0 && yarn add npm-run-all dotenv semver prisma@6.1.0
# You only need to copy next.config.js if you are NOT using the default configuration # You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/next.config.js . COPY --from=builder /app/next.config.js .

View file

@ -1,6 +1,6 @@
generator client { generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-3.0.x"] binaryTargets = ["native"]
} }
datasource db { datasource db {

View file

@ -1,6 +1,6 @@
generator client { generator client {
provider = "prisma-client-js" provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl-openssl-3.0.x", "linux-musl-arm64-openssl-3.0.x"] binaryTargets = ["native"]
} }
datasource db { datasource db {

1
next-env.d.ts vendored
View file

@ -1,6 +1,5 @@
/// <reference types="next" /> /// <reference types="next" />
/// <reference types="next/image-types/global" /> /// <reference types="next/image-types/global" />
/// <reference types="next/navigation-types/compat/navigation" />
// NOTE: This file should not be edited // NOTE: This file should not be edited
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. // see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information.

View file

@ -1,6 +1,5 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
require('dotenv').config(); require('dotenv').config();
const path = require('path');
const pkg = require('./package.json'); const pkg = require('./package.json');
const TRACKER_SCRIPT = '/script.js'; const TRACKER_SCRIPT = '/script.js';
@ -9,6 +8,7 @@ const basePath = process.env.BASE_PATH;
const collectApiEndpoint = process.env.COLLECT_API_ENDPOINT; const collectApiEndpoint = process.env.COLLECT_API_ENDPOINT;
const cloudMode = process.env.CLOUD_MODE; const cloudMode = process.env.CLOUD_MODE;
const cloudUrl = process.env.CLOUD_URL; const cloudUrl = process.env.CLOUD_URL;
const corsMaxAge = process.env.CORS_MAX_AGE;
const defaultLocale = process.env.DEFAULT_LOCALE; const defaultLocale = process.env.DEFAULT_LOCALE;
const disableLogin = process.env.DISABLE_LOGIN; const disableLogin = process.env.DISABLE_LOGIN;
const disableUI = process.env.DISABLE_UI; const disableUI = process.env.DISABLE_UI;
@ -60,6 +60,15 @@ const trackerHeaders = [
]; ];
const headers = [ const headers = [
{
source: '/api/:path*',
headers: [
{ key: 'Access-Control-Allow-Origin', value: '*' },
{ key: 'Access-Control-Allow-Headers', value: '*' },
{ key: 'Access-Control-Allow-Methods', value: 'GET, DELETE, POST, PUT' },
{ key: 'Access-Control-Max-Age', value: corsMaxAge || '86400' },
],
},
{ {
source: '/:path*', source: '/:path*',
headers: defaultHeaders, headers: defaultHeaders,
@ -169,27 +178,22 @@ const config = {
typescript: { typescript: {
ignoreBuildErrors: true, ignoreBuildErrors: true,
}, },
experimental: {
turbo: {
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
},
webpack(config) { webpack(config) {
const fileLoaderRule = config.module.rules.find(rule => rule.test?.test?.('.svg')); config.module.rules.push({
test: /\.svg$/,
config.module.rules.push( issuer: /\.(js|ts)x?$/,
{ use: ['@svgr/webpack'],
...fileLoaderRule, });
test: /\.svg$/i,
resourceQuery: /url/,
},
{
test: /\.svg$/i,
issuer: fileLoaderRule.issuer,
resourceQuery: { not: [...fileLoaderRule.resourceQuery.not, /url/] },
use: ['@svgr/webpack'],
},
);
fileLoaderRule.exclude = /\.svg$/i;
config.resolve.alias['public'] = path.resolve('./public');
return config; return config;
}, },
async headers() { async headers() {

View file

@ -1,6 +1,6 @@
{ {
"name": "umami", "name": "umami",
"version": "2.15.1", "version": "2.16.0",
"description": "A simple, fast, privacy-focused alternative to Google Analytics.", "description": "A simple, fast, privacy-focused alternative to Google Analytics.",
"author": "Umami Software, Inc. <hello@umami.is>", "author": "Umami Software, Inc. <hello@umami.is>",
"license": "MIT", "license": "MIT",
@ -10,7 +10,7 @@
"url": "https://github.com/umami-software/umami.git" "url": "https://github.com/umami-software/umami.git"
}, },
"scripts": { "scripts": {
"dev": "next dev -p 3000", "dev": "next dev -p 3000 --turbo",
"build": "npm-run-all check-env build-db check-db build-tracker build-geo build-app", "build": "npm-run-all check-env build-db check-db build-tracker build-geo build-app",
"start": "next start", "start": "next start",
"build-docker": "npm-run-all build-db build-tracker build-geo build-app", "build-docker": "npm-run-all build-db build-tracker build-geo build-app",
@ -63,21 +63,20 @@
"cacheDirectories": [ "cacheDirectories": [
".next/cache" ".next/cache"
], ],
"resolutions": {
"jackspeak": "2.1.1"
},
"dependencies": { "dependencies": {
"@clickhouse/client": "^1.4.1", "@clickhouse/client": "^1.10.1",
"@date-fns/utc": "^1.2.0", "@date-fns/utc": "^1.2.0",
"@dicebear/collection": "^9.2.1", "@dicebear/collection": "^9.2.1",
"@dicebear/core": "^9.2.1", "@dicebear/core": "^9.2.1",
"@fontsource/inter": "^4.5.15", "@fontsource/inter": "^4.5.15",
"@prisma/client": "5.22.0", "@hello-pangea/dnd": "^17.0.0",
"@prisma/extension-read-replicas": "^0.3.0", "@prisma/client": "6.1.0",
"@prisma/extension-read-replicas": "^0.4.0",
"@react-spring/web": "^9.7.3", "@react-spring/web": "^9.7.3",
"@tanstack/react-query": "^5.28.6", "@tanstack/react-query": "^5.28.6",
"@umami/prisma-client": "^0.14.0", "@umami/prisma-client": "^0.14.0",
"@umami/redis-client": "^0.24.0", "@umami/redis-client": "^0.26.0",
"bcryptjs": "^2.4.3",
"chalk": "^4.1.1", "chalk": "^4.1.1",
"chart.js": "^4.4.2", "chart.js": "^4.4.2",
"chartjs-adapter-date-fns": "^3.0.0", "chartjs-adapter-date-fns": "^3.0.0",
@ -99,17 +98,17 @@
"is-docker": "^3.0.0", "is-docker": "^3.0.0",
"is-localhost-ip": "^1.4.0", "is-localhost-ip": "^1.4.0",
"isbot": "^5.1.16", "isbot": "^5.1.16",
"jsonwebtoken": "^9.0.2",
"kafkajs": "^2.1.0", "kafkajs": "^2.1.0",
"maxmind": "^4.3.6", "maxmind": "^4.3.24",
"md5": "^2.3.0", "md5": "^2.3.0",
"next": "15.0.4", "next": "15.0.4",
"next-basics": "^0.39.0",
"node-fetch": "^3.2.8", "node-fetch": "^3.2.8",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"prisma": "5.22.0", "prisma": "6.1.0",
"pure-rand": "^6.1.0",
"react": "^19.0.0", "react": "^19.0.0",
"react-basics": "^0.125.0", "react-basics": "^0.126.0",
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
"react-error-boundary": "^4.0.4", "react-error-boundary": "^4.0.4",
"react-intl": "^6.5.5", "react-intl": "^6.5.5",
@ -118,9 +117,10 @@
"react-window": "^1.8.6", "react-window": "^1.8.6",
"request-ip": "^3.3.0", "request-ip": "^3.3.0",
"semver": "^7.5.4", "semver": "^7.5.4",
"serialize-error": "^12.0.0",
"thenby": "^1.3.4", "thenby": "^1.3.4",
"uuid": "^9.0.0", "uuid": "^9.0.0",
"yup": "^0.32.11", "zod": "^3.24.1",
"zustand": "^4.5.5" "zustand": "^4.5.5"
}, },
"devDependencies": { "devDependencies": {
@ -135,15 +135,16 @@
"@svgr/webpack": "^8.1.0", "@svgr/webpack": "^8.1.0",
"@types/cypress": "^1.1.3", "@types/cypress": "^1.1.3",
"@types/jest": "^29.5.14", "@types/jest": "^29.5.14",
"@types/node": "^20.9.0", "@types/node": "^22.13.4",
"@types/react": "^18.2.41", "@types/react": "^19.0.8",
"@types/react-dom": "^18.2.17", "@types/react-dom": "^19.0.2",
"@types/react-intl": "^3.0.0",
"@types/react-window": "^1.8.8", "@types/react-window": "^1.8.8",
"@typescript-eslint/eslint-plugin": "^6.7.3", "@typescript-eslint/eslint-plugin": "^6.7.3",
"@typescript-eslint/parser": "^6.7.3", "@typescript-eslint/parser": "^6.7.3",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"cypress": "^13.6.6", "cypress": "^13.6.6",
"esbuild": "^0.17.17", "esbuild": "^0.25.0",
"eslint": "^8.33.0", "eslint": "^8.33.0",
"eslint-config-next": "^14.0.4", "eslint-config-next": "^14.0.4",
"eslint-config-prettier": "^8.5.0", "eslint-config-prettier": "^8.5.0",

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
"label.access-code": [ "label.access-code": [
{ {
"type": 0, "type": 0,
"value": "Access code" "value": "पहुंच कोड"
} }
], ],
"label.actions": [ "label.actions": [
@ -14,19 +14,19 @@
"label.activity": [ "label.activity": [
{ {
"type": 0, "type": 0,
"value": "Activity log" "value": "गतिविधि लॉग"
} }
], ],
"label.add": [ "label.add": [
{ {
"type": 0, "type": 0,
"value": "Add" "value": "जोडो"
} }
], ],
"label.add-description": [ "label.add-description": [
{ {
"type": 0, "type": 0,
"value": "Add description" "value": "विवरण लिखें"
} }
], ],
"label.add-member": [ "label.add-member": [
@ -1006,7 +1006,7 @@
"label.reports": [ "label.reports": [
{ {
"type": 0, "type": 0,
"value": "Reports" "value": "प्रतिवेदन"
} }
], ],
"label.required": [ "label.required": [

View file

@ -19,13 +19,8 @@ const customResolver = resolve({
const aliasConfig = { const aliasConfig = {
entries: [ entries: [
{ find: /^app/, replacement: path.resolve('./src/app') }, { find: /^@/, replacement: path.resolve('./src/') },
{ find: /^components/, replacement: path.resolve('./src/components') },
{ find: /^hooks/, replacement: path.resolve('./src/hooks') },
{ find: /^lib/, replacement: path.resolve('./src/lib') },
{ find: /^store/, replacement: path.resolve('./src/store') },
{ find: /^public/, replacement: path.resolve('./public') }, { find: /^public/, replacement: path.resolve('./public') },
{ find: /^assets/, replacement: path.resolve('./src/assets') },
], ],
customResolver, customResolver,
}; };

View file

@ -1,94 +0,0 @@
/* eslint-disable no-console */
require('dotenv').config();
const { hashPassword } = require('next-basics');
const chalk = require('chalk');
const prompts = require('prompts');
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
const runQuery = async query => {
return query.catch(e => {
throw e;
});
};
const updateUserByUsername = (username, data) => {
return runQuery(
prisma.user.update({
where: {
username,
},
data,
}),
);
};
const changePassword = async (username, newPassword) => {
const password = hashPassword(newPassword);
return updateUserByUsername(username, { password });
};
const getUsernameAndPassword = async () => {
let [username, password] = process.argv.slice(2);
if (username && password) {
return { username, password };
}
const questions = [];
if (!username) {
questions.push({
type: 'text',
name: 'username',
message: 'Enter user to change password',
});
}
if (!password) {
questions.push(
{
type: 'password',
name: 'password',
message: 'Enter new password',
},
{
type: 'password',
name: 'confirmation',
message: 'Confirm new password',
},
);
}
const answers = await prompts(questions);
if (answers.password !== answers.confirmation) {
throw new Error(`Passwords don't match`);
}
return {
username: username || answers.username,
password: answers.password,
};
};
(async () => {
let username, password;
try {
({ username, password } = await getUsernameAndPassword());
} catch (error) {
console.log(chalk.redBright(error.message));
return;
}
try {
await changePassword(username, password);
console.log('Password changed for user', chalk.greenBright(username));
} catch (error) {
if (error.meta.cause.includes('Record to update not found')) {
console.log('User not found:', chalk.redBright(username));
} else {
throw error;
}
}
prisma.$disconnect();
})();

View file

@ -23,5 +23,5 @@ if (!process.env.SKIP_DB_CHECK && !process.env.DATABASE_TYPE) {
} }
if (process.env.CLOUD_MODE) { if (process.env.CLOUD_MODE) {
checkMissing(['CLOUD_URL', 'KAFKA_BROKER', 'KAFKA_URL', 'REDIS_URL']); checkMissing(['CLOUD_URL', 'KAFKA_BROKER', 'KAFKA_URL', 'REDIS_URL', 'KAFKA_SASL_MECHANISM']);
} }

View file

@ -2,7 +2,7 @@
import { Loading } from 'react-basics'; import { Loading } from 'react-basics';
import Script from 'next/script'; import Script from 'next/script';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import { useLogin, useConfig } from 'components/hooks'; import { useLogin, useConfig } from '@/components/hooks';
import UpdateNotice from './UpdateNotice'; import UpdateNotice from './UpdateNotice';
export function App({ children }) { export function App({ children }) {
@ -22,6 +22,10 @@ export function App({ children }) {
return null; return null;
} }
if (config.uiDisabled) {
return null;
}
return ( return (
<> <>
{children} {children}

View file

@ -1,17 +1,17 @@
'use client'; 'use client';
import { useEffect } from 'react';
import { Icon, Text } from 'react-basics'; import { Icon, Text } from 'react-basics';
import Link from 'next/link'; import Link from 'next/link';
import classNames from 'classnames'; import classNames from 'classnames';
import HamburgerButton from 'components/common/HamburgerButton'; import HamburgerButton from '@/components/common/HamburgerButton';
import ThemeButton from 'components/input/ThemeButton'; import ThemeButton from '@/components/input/ThemeButton';
import LanguageButton from 'components/input/LanguageButton'; import LanguageButton from '@/components/input/LanguageButton';
import ProfileButton from 'components/input/ProfileButton'; import ProfileButton from '@/components/input/ProfileButton';
import TeamsButton from 'components/input/TeamsButton'; import TeamsButton from '@/components/input/TeamsButton';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { useMessages, useNavigation, useTeamUrl } from 'components/hooks'; import { useMessages, useNavigation, useTeamUrl } from '@/components/hooks';
import { getItem, setItem } from '@/lib/storage';
import styles from './NavBar.module.css'; import styles from './NavBar.module.css';
import { useEffect } from 'react';
import { getItem, setItem } from 'next-basics';
export function NavBar() { export function NavBar() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();

View file

@ -1,10 +1,10 @@
import { useEffect, useCallback, useState } from 'react'; import { useEffect, useCallback, useState } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { Button } from 'react-basics'; import { Button } from 'react-basics';
import { setItem } from 'next-basics'; import { setItem } from '@/lib/storage';
import useStore, { checkVersion } from 'store/version'; import useStore, { checkVersion } from '@/store/version';
import { REPO_URL, VERSION_CHECK } from 'lib/constants'; import { REPO_URL, VERSION_CHECK } from '@/lib/constants';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { usePathname } from 'next/navigation'; import { usePathname } from 'next/navigation';
import styles from './UpdateNotice.module.css'; import styles from './UpdateNotice.module.css';
@ -14,6 +14,7 @@ export function UpdateNotice({ user, config }) {
const pathname = usePathname(); const pathname = usePathname();
const [dismissed, setDismissed] = useState(checked); const [dismissed, setDismissed] = useState(checked);
const allowUpdate = const allowUpdate =
process.env.NODE_ENV === 'production' &&
user?.isAdmin && user?.isAdmin &&
!config?.updatesDisabled && !config?.updatesDisabled &&
!pathname.includes('/share/') && !pathname.includes('/share/') &&

View file

@ -1,12 +1,12 @@
import { Button } from 'react-basics'; import { Button } from 'react-basics';
import Link from 'next/link'; import Link from 'next/link';
import Script from 'next/script'; import Script from 'next/script';
import WebsiteSelect from 'components/input/WebsiteSelect'; import WebsiteSelect from '@/components/input/WebsiteSelect';
import Page from 'components/layout/Page'; import Page from '@/components/layout/Page';
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import EventsChart from 'components/metrics/EventsChart'; import EventsChart from '@/components/metrics/EventsChart';
import WebsiteChart from '../websites/[websiteId]/WebsiteChart'; import WebsiteChart from '../websites/[websiteId]/WebsiteChart';
import { useApi, useNavigation } from 'components/hooks'; import { useApi, useNavigation } from '@/components/hooks';
import styles from './TestConsole.module.css'; import styles from './TestConsole.module.css';
export function TestConsole({ websiteId }: { websiteId: string }) { export function TestConsole({ websiteId }: { websiteId: string }) {

View file

@ -1,10 +1,10 @@
import { useState, useMemo, useEffect } from 'react'; import { useState, useMemo, useEffect } from 'react';
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd'; import { DragDropContext, Draggable, Droppable } from '@hello-pangea/dnd';
import classNames from 'classnames'; import classNames from 'classnames';
import { Button, Loading, Toggle, SearchField } from 'react-basics'; import { Button, Loading, Toggle, SearchField } from 'react-basics';
import { firstBy } from 'thenby'; import { firstBy } from 'thenby';
import useDashboard, { saveDashboard } from 'store/dashboard'; import useDashboard, { saveDashboard } from '@/store/dashboard';
import { useMessages, useWebsites } from 'components/hooks'; import { useMessages, useWebsites } from '@/components/hooks';
import styles from './DashboardEdit.module.css'; import styles from './DashboardEdit.module.css';
const DRAG_ID = 'dashboard-website-ordering'; const DRAG_ID = 'dashboard-website-ordering';

View file

@ -1,14 +1,14 @@
'use client'; 'use client';
import { Icon, Icons, Loading, Text } from 'react-basics'; import { Icon, Icons, Loading, Text } from 'react-basics';
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import Pager from 'components/common/Pager'; import Pager from '@/components/common/Pager';
import WebsiteChartList from '../websites/[websiteId]/WebsiteChartList'; import WebsiteChartList from '../websites/[websiteId]/WebsiteChartList';
import DashboardSettingsButton from 'app/(main)/dashboard/DashboardSettingsButton'; import DashboardSettingsButton from '@/app/(main)/dashboard/DashboardSettingsButton';
import DashboardEdit from 'app/(main)/dashboard/DashboardEdit'; import DashboardEdit from '@/app/(main)/dashboard/DashboardEdit';
import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import EmptyPlaceholder from '@/components/common/EmptyPlaceholder';
import { useMessages, useLocale, useTeamUrl, useWebsites } from 'components/hooks'; import { useMessages, useLocale, useTeamUrl, useWebsites } from '@/components/hooks';
import useDashboard from 'store/dashboard'; import useDashboard from '@/store/dashboard';
import LinkButton from 'components/common/LinkButton'; import LinkButton from '@/components/common/LinkButton';
export function DashboardPage() { export function DashboardPage() {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();

View file

@ -1,7 +1,7 @@
import { TooltipPopup, Icon, Text, Flexbox, Button } from 'react-basics'; import { TooltipPopup, Icon, Text, Flexbox, Button } from 'react-basics';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { saveDashboard } from 'store/dashboard'; import { saveDashboard } from '@/store/dashboard';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
export function DashboardSettingsButton() { export function DashboardSettingsButton() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();

View file

@ -1,14 +1,10 @@
import { Metadata } from 'next'; import { Metadata } from 'next';
import App from './App'; import App from './App';
import NavBar from './NavBar'; import NavBar from './NavBar';
import Page from 'components/layout/Page'; import Page from '@/components/layout/Page';
import styles from './layout.module.css'; import styles from './layout.module.css';
export default function ({ children }) { export default async function ({ children }) {
if (process.env.DISABLE_UI) {
return null;
}
return ( return (
<App> <App>
<main className={styles.layout}> <main className={styles.layout}>

View file

@ -1,8 +1,8 @@
import DateFilter from 'components/input/DateFilter'; import DateFilter from '@/components/input/DateFilter';
import { Button, Flexbox } from 'react-basics'; import { Button, Flexbox } from 'react-basics';
import { useDateRange, useMessages } from 'components/hooks'; import { useDateRange, useMessages } from '@/components/hooks';
import { DEFAULT_DATE_RANGE } from 'lib/constants'; import { DEFAULT_DATE_RANGE } from '@/lib/constants';
import { DateRange } from 'lib/types'; import { DateRange } from '@/lib/types';
import styles from './DateRangeSetting.module.css'; import styles from './DateRangeSetting.module.css';
export function DateRangeSetting() { export function DateRangeSetting() {

View file

@ -1,8 +1,8 @@
import { useState } from 'react'; import { useState } from 'react';
import { Button, Dropdown, Item, Flexbox } from 'react-basics'; import { Button, Dropdown, Item, Flexbox } from 'react-basics';
import { useLocale, useMessages } from 'components/hooks'; import { useLocale, useMessages } from '@/components/hooks';
import { DEFAULT_LOCALE } from 'lib/constants'; import { DEFAULT_LOCALE } from '@/lib/constants';
import { languages } from 'lib/lang'; import { languages } from '@/lib/lang';
import styles from './LanguageSetting.module.css'; import styles from './LanguageSetting.module.css';
export function LanguageSetting() { export function LanguageSetting() {

View file

@ -1,7 +1,7 @@
import { Button, Icon, Text, useToasts, ModalTrigger, Modal } from 'react-basics'; import { Button, Icon, Text, useToasts, ModalTrigger, Modal } from 'react-basics';
import PasswordEditForm from 'app/(main)/profile/PasswordEditForm'; import PasswordEditForm from '@/app/(main)/profile/PasswordEditForm';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
export function PasswordChangeButton() { export function PasswordChangeButton() {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();

View file

@ -1,6 +1,6 @@
import { useRef } from 'react'; import { useRef } from 'react';
import { Form, FormRow, FormInput, FormButtons, PasswordField, Button } from 'react-basics'; import { Form, FormRow, FormInput, FormButtons, PasswordField, Button } from 'react-basics';
import { useApi, useMessages } from 'components/hooks'; import { useApi, useMessages } from '@/components/hooks';
export function PasswordEditForm({ onSave, onClose }) { export function PasswordEditForm({ onSave, onClose }) {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();

View file

@ -1,5 +1,5 @@
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
export function ProfileHeader() { export function ProfileHeader() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();

View file

@ -1,11 +1,11 @@
import { Form, FormRow } from 'react-basics'; import { Form, FormRow } from 'react-basics';
import TimezoneSetting from 'app/(main)/profile/TimezoneSetting'; import TimezoneSetting from '@/app/(main)/profile/TimezoneSetting';
import DateRangeSetting from 'app/(main)/profile/DateRangeSetting'; import DateRangeSetting from '@/app/(main)/profile/DateRangeSetting';
import LanguageSetting from 'app/(main)/profile/LanguageSetting'; import LanguageSetting from '@/app/(main)/profile/LanguageSetting';
import ThemeSetting from 'app/(main)/profile/ThemeSetting'; import ThemeSetting from '@/app/(main)/profile/ThemeSetting';
import PasswordChangeButton from './PasswordChangeButton'; import PasswordChangeButton from './PasswordChangeButton';
import { useLogin, useMessages } from 'components/hooks'; import { useLogin, useMessages } from '@/components/hooks';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
export function ProfileSettings() { export function ProfileSettings() {
const { user } = useLogin(); const { user } = useLogin();

View file

@ -1,8 +1,8 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { Button, Icon } from 'react-basics'; import { Button, Icon } from 'react-basics';
import { useTheme } from 'components/hooks'; import { useTheme } from '@/components/hooks';
import Sun from 'assets/sun.svg'; import Sun from '@/assets/sun.svg';
import Moon from 'assets/moon.svg'; import Moon from '@/assets/moon.svg';
import styles from './ThemeSetting.module.css'; import styles from './ThemeSetting.module.css';
export function ThemeSetting() { export function ThemeSetting() {

View file

@ -1,7 +1,7 @@
import { useState } from 'react'; import { useState } from 'react';
import { Dropdown, Item, Button, Flexbox } from 'react-basics'; import { Dropdown, Item, Button, Flexbox } from 'react-basics';
import { useTimezone, useMessages } from 'components/hooks'; import { useTimezone, useMessages } from '@/components/hooks';
import { getTimezone } from 'lib/date'; import { getTimezone } from '@/lib/date';
import styles from './TimezoneSetting.module.css'; import styles from './TimezoneSetting.module.css';
const timezones = Intl.supportedValuesOf('timeZone'); const timezones = Intl.supportedValuesOf('timeZone');

View file

@ -1,6 +1,6 @@
import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
import { useApi, useMessages, useModified } from 'components/hooks'; import { useApi, useMessages, useModified } from '@/components/hooks';
import ConfirmationForm from 'components/common/ConfirmationForm'; import ConfirmationForm from '@/components/common/ConfirmationForm';
export function ReportDeleteButton({ export function ReportDeleteButton({
reportId, reportId,
@ -11,7 +11,7 @@ export function ReportDeleteButton({
reportName: string; reportName: string;
onDelete?: () => void; onDelete?: () => void;
}) { }) {
const { formatMessage, labels, messages, FormattedMessage } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const { del, useMutation } = useApi(); const { del, useMutation } = useApi();
const { mutate, isPending, error } = useMutation({ const { mutate, isPending, error } = useMutation({
mutationFn: reportId => del(`/reports/${reportId}`), mutationFn: reportId => del(`/reports/${reportId}`),
@ -39,12 +39,7 @@ export function ReportDeleteButton({
<Modal title={formatMessage(labels.deleteReport)}> <Modal title={formatMessage(labels.deleteReport)}>
{(close: () => void) => ( {(close: () => void) => (
<ConfirmationForm <ConfirmationForm
message={ message={formatMessage(messages.confirmDelete, { target: <b>{reportName}</b> })}
<FormattedMessage
{...messages.confirmDelete}
values={{ target: <b>{reportName}</b> }}
/>
}
isLoading={isPending} isLoading={isPending}
error={error} error={error}
onConfirm={handleConfirm.bind(null, close)} onConfirm={handleConfirm.bind(null, close)}

View file

@ -1,6 +1,6 @@
import { useReports } from 'components/hooks'; import { useReports } from '@/components/hooks';
import ReportsTable from './ReportsTable'; import ReportsTable from './ReportsTable';
import DataTable from 'components/common/DataTable'; import DataTable from '@/components/common/DataTable';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
export default function ReportsDataTable({ export default function ReportsDataTable({

View file

@ -1,8 +1,8 @@
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import { Icon, Icons, Text } from 'react-basics'; import { Icon, Icons, Text } from 'react-basics';
import { useLogin, useMessages, useTeamUrl } from 'components/hooks'; import { useLogin, useMessages, useTeamUrl } from '@/components/hooks';
import LinkButton from 'components/common/LinkButton'; import LinkButton from '@/components/common/LinkButton';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
export function ReportsHeader() { export function ReportsHeader() {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();

View file

@ -2,7 +2,7 @@
import { Metadata } from 'next'; import { Metadata } from 'next';
import ReportsHeader from './ReportsHeader'; import ReportsHeader from './ReportsHeader';
import ReportsDataTable from './ReportsDataTable'; import ReportsDataTable from './ReportsDataTable';
import { useTeamUrl } from 'components/hooks'; import { useTeamUrl } from '@/components/hooks';
export default function ReportsPage() { export default function ReportsPage() {
const { teamId } = useTeamUrl(); const { teamId } = useTeamUrl();

View file

@ -1,7 +1,7 @@
import { GridColumn, GridTable, Icon, Icons, Text } from 'react-basics'; import { GridColumn, GridTable, Icon, Icons, Text } from 'react-basics';
import LinkButton from 'components/common/LinkButton'; import LinkButton from '@/components/common/LinkButton';
import { useMessages, useLogin, useTeamUrl } from 'components/hooks'; import { useMessages, useLogin, useTeamUrl } from '@/components/hooks';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
import ReportDeleteButton from './ReportDeleteButton'; import ReportDeleteButton from './ReportDeleteButton';
export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomain?: boolean }) { export function ReportsTable({ data = [], showDomain }: { data: any[]; showDomain?: boolean }) {

View file

@ -1,9 +1,9 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { FormRow } from 'react-basics'; import { FormRow } from 'react-basics';
import { parseDateRange } from 'lib/date'; import { parseDateRange } from '@/lib/date';
import DateFilter from 'components/input/DateFilter'; import DateFilter from '@/components/input/DateFilter';
import WebsiteSelect from 'components/input/WebsiteSelect'; import WebsiteSelect from '@/components/input/WebsiteSelect';
import { useMessages, useTeamUrl, useWebsite } from 'components/hooks'; import { useMessages, useTeamUrl, useWebsite } from '@/components/hooks';
import { ReportContext } from './Report'; import { ReportContext } from './Report';
import styles from './BaseParameters.module.css'; import styles from './BaseParameters.module.css';

View file

@ -1,6 +1,6 @@
import { useState } from 'react'; import { useState } from 'react';
import { createPortal } from 'react-dom'; import { createPortal } from 'react-dom';
import { REPORT_PARAMETERS } from 'lib/constants'; import { REPORT_PARAMETERS } from '@/lib/constants';
import PopupForm from './PopupForm'; import PopupForm from './PopupForm';
import FieldSelectForm from './FieldSelectForm'; import FieldSelectForm from './FieldSelectForm';

View file

@ -1,5 +1,5 @@
import { Form, FormRow, Menu, Item } from 'react-basics'; import { Form, FormRow, Menu, Item } from 'react-basics';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
export default function FieldAggregateForm({ export default function FieldAggregateForm({
name, name,

View file

@ -1,7 +1,7 @@
import { useFilters, useFormat, useLocale, useMessages, useWebsiteValues } from 'components/hooks';
import { OPERATORS } from 'lib/constants';
import { isEqualsOperator } from 'lib/params';
import { useMemo, useState } from 'react'; import { useMemo, useState } from 'react';
import { useFilters, useFormat, useMessages, useWebsiteValues } from '@/components/hooks';
import { OPERATORS } from '@/lib/constants';
import { isEqualsOperator } from '@/lib/params';
import { import {
Button, Button,
Dropdown, Dropdown,
@ -55,7 +55,6 @@ export default function FieldFilterEditForm({
const [selected, setSelected] = useState(isEquals ? value : ''); const [selected, setSelected] = useState(isEquals ? value : '');
const { filters } = useFilters(); const { filters } = useFilters();
const { formatValue } = useFormat(); const { formatValue } = useFormat();
const { locale } = useLocale();
const isDisabled = !operator || (isEquals && !selected) || (!isEquals && !value); const isDisabled = !operator || (isEquals && !selected) || (!isEquals && !value);
const { const {
data: values = [], data: values = [],
@ -80,29 +79,17 @@ export default function FieldFilterEditForm({
}; };
const formattedValues = useMemo(() => { const formattedValues = useMemo(() => {
if (!values) { return values.reduce((obj: { [x: string]: string }, { value }: { value: string }) => {
return {}; obj[value] = formatValue(value, name);
}
const formatted = {};
const format = (val: string) => {
formatted[val] = formatValue(val, name);
return formatted[val];
};
if (values?.length !== 1) { return obj;
const { compare } = new Intl.Collator(locale, { numeric: true }); }, {});
values.sort((a, b) => compare(formatted[a] ?? format(a), formatted[b] ?? format(b))); }, [formatValue, name, values]);
} else {
format(values[0]);
}
return formatted;
}, [formatValue, locale, name, values]);
const filteredValues = useMemo(() => { const filteredValues = useMemo(() => {
return value return value
? values.filter((n: string | number) => ? values.filter((n: string | number) =>
formattedValues[n].toLowerCase().includes(value.toLowerCase()), formattedValues[n]?.toLowerCase()?.includes(value.toLowerCase()),
) )
: values; : values;
}, [value, formattedValues]); }, [value, formattedValues]);
@ -226,7 +213,7 @@ const ResultsMenu = ({ values, type, isLoading, onSelect }) => {
return ( return (
<Menu className={styles.menu} variant="popup" onSelect={onSelect}> <Menu className={styles.menu} variant="popup" onSelect={onSelect}>
{values?.map((value: any) => { {values?.map(({ value }) => {
return <Item key={value}>{formatValue(value, type)}</Item>; return <Item key={value}>{formatValue(value, type)}</Item>;
})} })}
</Menu> </Menu>

View file

@ -1,5 +1,5 @@
import { useFields, useMessages } from 'components/hooks'; import { useFields, useMessages } from '@/components/hooks';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { useContext } from 'react'; import { useContext } from 'react';
import { Button, FormRow, Icon, Popup, PopupTrigger } from 'react-basics'; import { Button, FormRow, Icon, Popup, PopupTrigger } from 'react-basics';
import FieldSelectForm from '../[reportId]/FieldSelectForm'; import FieldSelectForm from '../[reportId]/FieldSelectForm';

View file

@ -1,5 +1,5 @@
import { Menu, Item, Form, FormRow } from 'react-basics'; import { Menu, Item, Form, FormRow } from 'react-basics';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import styles from './FieldSelectForm.module.css'; import styles from './FieldSelectForm.module.css';
import { Key } from 'react'; import { Key } from 'react';

View file

@ -1,13 +1,13 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useMessages, useFormat, useFilters, useFields } from 'components/hooks'; import { useMessages, useFormat, useFilters, useFields } from '@/components/hooks';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { Button, FormRow, Icon, Popup, PopupTrigger } from 'react-basics'; import { Button, FormRow, Icon, Popup, PopupTrigger } from 'react-basics';
import FilterSelectForm from '../[reportId]/FilterSelectForm'; import FilterSelectForm from '../[reportId]/FilterSelectForm';
import ParameterList from '../[reportId]/ParameterList'; import ParameterList from '../[reportId]/ParameterList';
import PopupForm from '../[reportId]/PopupForm'; import PopupForm from '../[reportId]/PopupForm';
import { ReportContext } from './Report'; import { ReportContext } from './Report';
import FieldFilterEditForm from '../[reportId]/FieldFilterEditForm'; import FieldFilterEditForm from '../[reportId]/FieldFilterEditForm';
import { isSearchOperator } from 'lib/params'; import { isSearchOperator } from '@/lib/params';
import styles from './FilterParameters.module.css'; import styles from './FilterParameters.module.css';
export function FilterParameters() { export function FilterParameters() {

View file

@ -1,8 +1,8 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Icon } from 'react-basics'; import { Icon } from 'react-basics';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import Empty from 'components/common/Empty'; import Empty from '@/components/common/Empty';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import styles from './ParameterList.module.css'; import styles from './ParameterList.module.css';
import classNames from 'classnames'; import classNames from 'classnames';

View file

@ -1,7 +1,7 @@
import { createContext, ReactNode } from 'react'; import { createContext, ReactNode } from 'react';
import { Loading } from 'react-basics'; import { Loading } from 'react-basics';
import classNames from 'classnames'; import classNames from 'classnames';
import { useReport } from 'components/hooks'; import { useReport } from '@/components/hooks';
import styles from './Report.module.css'; import styles from './Report.module.css';
export const ReportContext = createContext(null); export const ReportContext = createContext(null);

View file

@ -1,10 +1,10 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { Icon, LoadingButton, InlineEditField, useToasts } from 'react-basics'; import { Icon, LoadingButton, InlineEditField, useToasts } from 'react-basics';
import { useMessages, useApi, useNavigation, useTeamUrl } from 'components/hooks'; import { useMessages, useApi, useNavigation, useTeamUrl } from '@/components/hooks';
import { ReportContext } from './Report'; import { ReportContext } from './Report';
import styles from './ReportHeader.module.css'; import styles from './ReportHeader.module.css';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
import Breadcrumb from 'components/common/Breadcrumb'; import Breadcrumb from '@/components/common/Breadcrumb';
export function ReportHeader({ icon }) { export function ReportHeader({ icon }) {
const { report, updateReport } = useContext(ReportContext); const { report, updateReport } = useContext(ReportContext);

View file

@ -1,5 +1,5 @@
'use client'; 'use client';
import { useReport } from 'components/hooks'; import { useReport } from '@/components/hooks';
import EventDataReport from '../event-data/EventDataReport'; import EventDataReport from '../event-data/EventDataReport';
import FunnelReport from '../funnel/FunnelReport'; import FunnelReport from '../funnel/FunnelReport';
import GoalReport from '../goals/GoalsReport'; import GoalReport from '../goals/GoalsReport';

View file

@ -1,12 +1,12 @@
import Funnel from 'assets/funnel.svg'; import Funnel from '@/assets/funnel.svg';
import Money from 'assets/money.svg'; import Money from '@/assets/money.svg';
import Lightbulb from 'assets/lightbulb.svg'; import Lightbulb from '@/assets/lightbulb.svg';
import Magnet from 'assets/magnet.svg'; import Magnet from '@/assets/magnet.svg';
import Path from 'assets/path.svg'; import Path from '@/assets/path.svg';
import Tag from 'assets/tag.svg'; import Tag from '@/assets/tag.svg';
import Target from 'assets/target.svg'; import Target from '@/assets/target.svg';
import { useMessages, useTeamUrl } from 'components/hooks'; import { useMessages, useTeamUrl } from '@/components/hooks';
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import Link from 'next/link'; import Link from 'next/link';
import { Button, Icon, Icons, Text } from 'react-basics'; import { Button, Icon, Icons, Text } from 'react-basics';
import styles from './ReportTemplates.module.css'; import styles from './ReportTemplates.module.css';

View file

@ -1,9 +1,9 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { Form, FormRow, FormButtons, SubmitButton, PopupTrigger, Icon, Popup } from 'react-basics'; import { Form, FormRow, FormButtons, SubmitButton, PopupTrigger, Icon, Popup } from 'react-basics';
import Empty from 'components/common/Empty'; import Empty from '@/components/common/Empty';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { useApi, useMessages } from 'components/hooks'; import { useApi, useMessages } from '@/components/hooks';
import { DATA_TYPES, REPORT_PARAMETERS } from 'lib/constants'; import { DATA_TYPES, REPORT_PARAMETERS } from '@/lib/constants';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import FieldAddForm from '../[reportId]/FieldAddForm'; import FieldAddForm from '../[reportId]/FieldAddForm';
import ParameterList from '../[reportId]/ParameterList'; import ParameterList from '../[reportId]/ParameterList';

View file

@ -4,7 +4,7 @@ import ReportMenu from '../[reportId]/ReportMenu';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import EventDataParameters from './EventDataParameters'; import EventDataParameters from './EventDataParameters';
import EventDataTable from './EventDataTable'; import EventDataTable from './EventDataTable';
import Nodes from 'assets/nodes.svg'; import Nodes from '@/assets/nodes.svg';
const defaultParameters = { const defaultParameters = {
type: 'event-data', type: 'event-data',

View file

@ -1,6 +1,6 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { GridTable, GridColumn } from 'react-basics'; import { GridTable, GridColumn } from 'react-basics';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
export function EventDataTable() { export function EventDataTable() {

View file

@ -1,8 +1,8 @@
import { useContext } from 'react'; import { useContext } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { formatLongNumber } from 'lib/format'; import { formatLongNumber } from '@/lib/format';
import styles from './FunnelChart.module.css'; import styles from './FunnelChart.module.css';
export interface FunnelChartProps { export interface FunnelChartProps {

View file

@ -1,5 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { import {
Icon, Icon,
Form, Form,
@ -12,7 +12,7 @@ import {
TextField, TextField,
Button, Button,
} from 'react-basics'; } from 'react-basics';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import FunnelStepAddForm from './FunnelStepAddForm'; import FunnelStepAddForm from './FunnelStepAddForm';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import BaseParameters from '../[reportId]/BaseParameters'; import BaseParameters from '../[reportId]/BaseParameters';

View file

@ -4,8 +4,8 @@ import Report from '../[reportId]/Report';
import ReportHeader from '../[reportId]/ReportHeader'; import ReportHeader from '../[reportId]/ReportHeader';
import ReportMenu from '../[reportId]/ReportMenu'; import ReportMenu from '../[reportId]/ReportMenu';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import Funnel from 'assets/funnel.svg'; import Funnel from '@/assets/funnel.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
const defaultParameters = { const defaultParameters = {
type: REPORT_TYPES.funnel, type: REPORT_TYPES.funnel,

View file

@ -1,5 +1,5 @@
import { useState } from 'react'; import { useState } from 'react';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { Button, FormRow, TextField, Flexbox, Dropdown, Item } from 'react-basics'; import { Button, FormRow, TextField, Flexbox, Dropdown, Item } from 'react-basics';
import styles from './FunnelStepAddForm.module.css'; import styles from './FunnelStepAddForm.module.css';

View file

@ -1,4 +1,4 @@
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { useState } from 'react'; import { useState } from 'react';
import { Button, Dropdown, Flexbox, FormRow, Item, TextField } from 'react-basics'; import { Button, Dropdown, Flexbox, FormRow, Item, TextField } from 'react-basics';
import styles from './GoalsAddForm.module.css'; import styles from './GoalsAddForm.module.css';

View file

@ -1,8 +1,8 @@
import { useContext } from 'react'; import { useContext } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { formatLongNumber } from 'lib/format'; import { formatLongNumber } from '@/lib/format';
import styles from './GoalsChart.module.css'; import styles from './GoalsChart.module.css';
export function GoalsChart({ className }: { className?: string; isLoading?: boolean }) { export function GoalsChart({ className }: { className?: string; isLoading?: boolean }) {

View file

@ -1,6 +1,6 @@
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { formatNumber } from 'lib/format'; import { formatNumber } from '@/lib/format';
import { useContext } from 'react'; import { useContext } from 'react';
import { import {
Button, Button,

View file

@ -4,8 +4,8 @@ import Report from '../[reportId]/Report';
import ReportHeader from '../[reportId]/ReportHeader'; import ReportHeader from '../[reportId]/ReportHeader';
import ReportMenu from '../[reportId]/ReportMenu'; import ReportMenu from '../[reportId]/ReportMenu';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import Target from 'assets/target.svg'; import Target from '@/assets/target.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
const defaultParameters = { const defaultParameters = {
type: REPORT_TYPES.goals, type: REPORT_TYPES.goals,

View file

@ -1,4 +1,4 @@
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { useContext } from 'react'; import { useContext } from 'react';
import { Form, FormButtons, SubmitButton } from 'react-basics'; import { Form, FormButtons, SubmitButton } from 'react-basics';
import BaseParameters from '../[reportId]/BaseParameters'; import BaseParameters from '../[reportId]/BaseParameters';

View file

@ -4,8 +4,8 @@ import ReportMenu from '../[reportId]/ReportMenu';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import InsightsParameters from './InsightsParameters'; import InsightsParameters from './InsightsParameters';
import InsightsTable from './InsightsTable'; import InsightsTable from './InsightsTable';
import Lightbulb from 'assets/lightbulb.svg'; import Lightbulb from '@/assets/lightbulb.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
const defaultParameters = { const defaultParameters = {
type: REPORT_TYPES.insights, type: REPORT_TYPES.insights,

View file

@ -1,9 +1,9 @@
import { useContext, useEffect, useState } from 'react'; import { useContext, useEffect, useState } from 'react';
import { GridTable, GridColumn } from 'react-basics'; import { GridTable, GridColumn } from 'react-basics';
import { useFormat, useMessages } from 'components/hooks'; import { useFormat, useMessages } from '@/components/hooks';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import EmptyPlaceholder from '@/components/common/EmptyPlaceholder';
import { formatShortTime } from 'lib/format'; import { formatShortTime } from '@/lib/format';
export function InsightsTable() { export function InsightsTable() {
const [fields, setFields] = useState([]); const [fields, setFields] = useState([]);

View file

@ -1,5 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { import {
Dropdown, Dropdown,
Form, Form,

View file

@ -5,8 +5,8 @@ import ReportMenu from '../[reportId]/ReportMenu';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import JourneyParameters from './JourneyParameters'; import JourneyParameters from './JourneyParameters';
import JourneyView from './JourneyView'; import JourneyView from './JourneyView';
import Path from 'assets/path.svg'; import Path from '@/assets/path.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
const defaultParameters = { const defaultParameters = {
type: REPORT_TYPES.journey, type: REPORT_TYPES.journey,

View file

@ -2,11 +2,11 @@ import { useContext, useMemo, useState } from 'react';
import { TextOverflow, TooltipPopup } from 'react-basics'; import { TextOverflow, TooltipPopup } from 'react-basics';
import { firstBy } from 'thenby'; import { firstBy } from 'thenby';
import classNames from 'classnames'; import classNames from 'classnames';
import { useEscapeKey, useMessages } from 'components/hooks'; import { useEscapeKey, useMessages } from '@/components/hooks';
import { objectToArray } from 'lib/data'; import { objectToArray } from '@/lib/data';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import styles from './JourneyView.module.css'; import styles from './JourneyView.module.css';
import { formatLongNumber } from 'lib/format'; import { formatLongNumber } from '@/lib/format';
const NODE_HEIGHT = 60; const NODE_HEIGHT = 60;
const NODE_GAP = 10; const NODE_GAP = 10;

View file

@ -1,10 +1,10 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics'; import { Form, FormButtons, FormRow, SubmitButton } from 'react-basics';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { MonthSelect } from 'components/input/MonthSelect'; import { MonthSelect } from '@/components/input/MonthSelect';
import BaseParameters from '../[reportId]/BaseParameters'; import BaseParameters from '../[reportId]/BaseParameters';
import { parseDateRange } from 'lib/date'; import { parseDateRange } from '@/lib/date';
export function RetentionParameters() { export function RetentionParameters() {
const { report, runReport, isRunning, updateReport } = useContext(ReportContext); const { report, runReport, isRunning, updateReport } = useContext(ReportContext);

View file

@ -4,9 +4,9 @@ import Report from '../[reportId]/Report';
import ReportHeader from '../[reportId]/ReportHeader'; import ReportHeader from '../[reportId]/ReportHeader';
import ReportMenu from '../[reportId]/ReportMenu'; import ReportMenu from '../[reportId]/ReportMenu';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import Magnet from 'assets/magnet.svg'; import Magnet from '@/assets/magnet.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
import { parseDateRange } from 'lib/date'; import { parseDateRange } from '@/lib/date';
import { endOfMonth, startOfMonth } from 'date-fns'; import { endOfMonth, startOfMonth } from 'date-fns';
const defaultParameters = { const defaultParameters = {

View file

@ -1,9 +1,9 @@
import { useContext } from 'react'; import { useContext } from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import EmptyPlaceholder from '@/components/common/EmptyPlaceholder';
import { useMessages, useLocale } from 'components/hooks'; import { useMessages, useLocale } from '@/components/hooks';
import { formatDate } from 'lib/date'; import { formatDate } from '@/lib/date';
import styles from './RetentionTable.module.css'; import styles from './RetentionTable.module.css';
const DAYS = [1, 2, 3, 4, 5, 6, 7, 14, 21, 28]; const DAYS = [1, 2, 3, 4, 5, 6, 7, 14, 21, 28];

View file

@ -1,5 +1,5 @@
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import useRevenueValues from 'components/hooks/queries/useRevenueValues'; import useRevenueValues from '@/components/hooks/queries/useRevenueValues';
import { useContext } from 'react'; import { useContext } from 'react';
import { Dropdown, Form, FormButtons, FormInput, FormRow, Item, SubmitButton } from 'react-basics'; import { Dropdown, Form, FormButtons, FormInput, FormRow, Item, SubmitButton } from 'react-basics';
import BaseParameters from '../[reportId]/BaseParameters'; import BaseParameters from '../[reportId]/BaseParameters';

View file

@ -1,5 +1,5 @@
import Money from 'assets/money.svg'; import Money from '@/assets/money.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
import Report from '../[reportId]/Report'; import Report from '../[reportId]/Report';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import ReportHeader from '../[reportId]/ReportHeader'; import ReportHeader from '../[reportId]/ReportHeader';

View file

@ -1,9 +1,9 @@
import EmptyPlaceholder from 'components/common/EmptyPlaceholder'; import EmptyPlaceholder from '@/components/common/EmptyPlaceholder';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { useContext } from 'react'; import { useContext } from 'react';
import { GridColumn, GridTable } from 'react-basics'; import { GridColumn, GridTable } from 'react-basics';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { formatLongCurrency } from 'lib/format'; import { formatLongCurrency } from '@/lib/format';
export function RevenueTable() { export function RevenueTable() {
const { report } = useContext(ReportContext); const { report } = useContext(ReportContext);

View file

@ -1,16 +1,16 @@
import classNames from 'classnames'; import classNames from 'classnames';
import { colord } from 'colord'; import { colord } from 'colord';
import BarChart from 'components/charts/BarChart'; import BarChart from '@/components/charts/BarChart';
import PieChart from 'components/charts/PieChart'; import PieChart from '@/components/charts/PieChart';
import TypeIcon from 'components/common/TypeIcon'; import TypeIcon from '@/components/common/TypeIcon';
import { useCountryNames, useLocale, useMessages } from 'components/hooks'; import { useCountryNames, useLocale, useMessages } from '@/components/hooks';
import { GridRow } from 'components/layout/Grid'; import { GridRow } from '@/components/layout/Grid';
import ListTable from 'components/metrics/ListTable'; import ListTable from '@/components/metrics/ListTable';
import MetricCard from 'components/metrics/MetricCard'; import MetricCard from '@/components/metrics/MetricCard';
import MetricsBar from 'components/metrics/MetricsBar'; import MetricsBar from '@/components/metrics/MetricsBar';
import { renderDateLabels } from 'lib/charts'; import { renderDateLabels } from '@/lib/charts';
import { CHART_COLORS } from 'lib/constants'; import { CHART_COLORS } from '@/lib/constants';
import { formatLongCurrency, formatLongNumber } from 'lib/format'; import { formatLongCurrency, formatLongNumber } from '@/lib/format';
import { useCallback, useContext, useMemo } from 'react'; import { useCallback, useContext, useMemo } from 'react';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import RevenueTable from './RevenueTable'; import RevenueTable from './RevenueTable';

View file

@ -1,5 +1,5 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import { Form, FormButtons, SubmitButton } from 'react-basics'; import { Form, FormButtons, SubmitButton } from 'react-basics';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import BaseParameters from '../[reportId]/BaseParameters'; import BaseParameters from '../[reportId]/BaseParameters';

View file

@ -5,8 +5,8 @@ import ReportMenu from '../[reportId]/ReportMenu';
import ReportBody from '../[reportId]/ReportBody'; import ReportBody from '../[reportId]/ReportBody';
import UTMParameters from './UTMParameters'; import UTMParameters from './UTMParameters';
import UTMView from './UTMView'; import UTMView from './UTMView';
import Tag from 'assets/tag.svg'; import Tag from '@/assets/tag.svg';
import { REPORT_TYPES } from 'lib/constants'; import { REPORT_TYPES } from '@/lib/constants';
const defaultParameters = { const defaultParameters = {
type: REPORT_TYPES.utm, type: REPORT_TYPES.utm,

View file

@ -1,11 +1,11 @@
import { useContext } from 'react'; import { useContext } from 'react';
import { firstBy } from 'thenby'; import { firstBy } from 'thenby';
import { ReportContext } from '../[reportId]/Report'; import { ReportContext } from '../[reportId]/Report';
import { CHART_COLORS, UTM_PARAMS } from 'lib/constants'; import { CHART_COLORS, UTM_PARAMS } from '@/lib/constants';
import PieChart from 'components/charts/PieChart'; import PieChart from '@/components/charts/PieChart';
import ListTable from 'components/metrics/ListTable'; import ListTable from '@/components/metrics/ListTable';
import styles from './UTMView.module.css'; import styles from './UTMView.module.css';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
function toArray(data: { [key: string]: number } = {}) { function toArray(data: { [key: string]: number } = {}) {
return Object.keys(data) return Object.keys(data)

View file

@ -1,7 +1,7 @@
'use client'; 'use client';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { useLogin, useMessages } from 'components/hooks'; import { useLogin, useMessages } from '@/components/hooks';
import MenuLayout from 'components/layout/MenuLayout'; import MenuLayout from '@/components/layout/MenuLayout';
export default function SettingsLayout({ children }: { children: ReactNode }) { export default function SettingsLayout({ children }: { children: ReactNode }) {
const { user } = useLogin(); const { user } = useLogin();

View file

@ -1,4 +1,4 @@
import { useApi, useMessages } from 'components/hooks'; import { useApi, useMessages } from '@/components/hooks';
import { import {
Button, Button,
Form, Form,

View file

@ -8,10 +8,10 @@ import {
Button, Button,
SubmitButton, SubmitButton,
} from 'react-basics'; } from 'react-basics';
import { useApi, useMessages, useModified } from 'components/hooks'; import { useApi, useMessages, useModified } from '@/components/hooks';
export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) { export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose: () => void }) {
const { formatMessage, labels, getMessage } = useMessages(); const { formatMessage, labels } = useMessages();
const { post, useMutation } = useApi(); const { post, useMutation } = useApi();
const { mutate, error } = useMutation({ mutationFn: (data: any) => post('/teams/join', data) }); const { mutate, error } = useMutation({ mutationFn: (data: any) => post('/teams/join', data) });
const ref = useRef(null); const ref = useRef(null);
@ -28,7 +28,7 @@ export function TeamJoinForm({ onSave, onClose }: { onSave: () => void; onClose:
}; };
return ( return (
<Form ref={ref} onSubmit={handleSubmit} error={error && getMessage(error)}> <Form ref={ref} onSubmit={handleSubmit} error={error}>
<FormRow label={formatMessage(labels.accessCode)}> <FormRow label={formatMessage(labels.accessCode)}>
<FormInput name="accessCode" rules={{ required: formatMessage(labels.required) }}> <FormInput name="accessCode" rules={{ required: formatMessage(labels.required) }}>
<TextField autoComplete="off" /> <TextField autoComplete="off" />

View file

@ -1,4 +1,4 @@
import { useLocale, useLogin, useMessages, useModified } from 'components/hooks'; import { useLocale, useLogin, useMessages, useModified } from '@/components/hooks';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
import TeamDeleteForm from './TeamLeaveForm'; import TeamDeleteForm from './TeamLeaveForm';

View file

@ -1,5 +1,5 @@
import { useApi, useMessages, useModified } from 'components/hooks'; import { useApi, useMessages, useModified } from '@/components/hooks';
import ConfirmationForm from 'components/common/ConfirmationForm'; import ConfirmationForm from '@/components/common/ConfirmationForm';
export function TeamLeaveForm({ export function TeamLeaveForm({
teamId, teamId,
@ -14,7 +14,7 @@ export function TeamLeaveForm({
onSave: () => void; onSave: () => void;
onClose: () => void; onClose: () => void;
}) { }) {
const { formatMessage, labels, messages, FormattedMessage } = useMessages(); const { formatMessage, labels, messages } = useMessages();
const { del, useMutation } = useApi(); const { del, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({ const { mutate, error, isPending } = useMutation({
mutationFn: () => del(`/teams/${teamId}/users/${userId}`), mutationFn: () => del(`/teams/${teamId}/users/${userId}`),
@ -34,9 +34,7 @@ export function TeamLeaveForm({
return ( return (
<ConfirmationForm <ConfirmationForm
buttonLabel={formatMessage(labels.leave)} buttonLabel={formatMessage(labels.leave)}
message={ message={formatMessage(messages.confirmLeave, { target: <b>{teamName}</b> })}
<FormattedMessage {...messages.confirmLeave} values={{ target: <b>{teamName}</b> }} />
}
onConfirm={handleConfirm} onConfirm={handleConfirm}
onClose={onClose} onClose={onClose}
isLoading={isPending} isLoading={isPending}

View file

@ -1,8 +1,8 @@
import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { useMessages, useModified } from 'components/hooks'; import { useMessages, useModified } from '@/components/hooks';
import TeamAddForm from './TeamAddForm'; import TeamAddForm from './TeamAddForm';
import { messages } from 'components/messages'; import { messages } from '@/components/messages';
export function TeamsAddButton({ onSave }: { onSave?: () => void }) { export function TeamsAddButton({ onSave }: { onSave?: () => void }) {
const { formatMessage, labels } = useMessages(); const { formatMessage, labels } = useMessages();

View file

@ -1,6 +1,6 @@
import DataTable from 'components/common/DataTable'; import DataTable from '@/components/common/DataTable';
import TeamsTable from 'app/(main)/settings/teams/TeamsTable'; import TeamsTable from '@/app/(main)/settings/teams/TeamsTable';
import { useLogin, useTeams } from 'components/hooks'; import { useLogin, useTeams } from '@/components/hooks';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
export function TeamsDataTable({ export function TeamsDataTable({

View file

@ -1,7 +1,7 @@
import { Flexbox } from 'react-basics'; import { Flexbox } from 'react-basics';
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
import { useLogin, useMessages } from 'components/hooks'; import { useLogin, useMessages } from '@/components/hooks';
import TeamsJoinButton from './TeamsJoinButton'; import TeamsJoinButton from './TeamsJoinButton';
import TeamsAddButton from './TeamsAddButton'; import TeamsAddButton from './TeamsAddButton';

View file

@ -1,6 +1,6 @@
import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import { Button, Icon, Modal, ModalTrigger, Text, useToasts } from 'react-basics';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { useMessages, useModified } from 'components/hooks'; import { useMessages, useModified } from '@/components/hooks';
import TeamJoinForm from './TeamJoinForm'; import TeamJoinForm from './TeamJoinForm';
export function TeamsJoinButton() { export function TeamsJoinButton() {

View file

@ -1,8 +1,8 @@
import { GridColumn, GridTable, Icon, Text } from 'react-basics'; import { GridColumn, GridTable, Icon, Text } from 'react-basics';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
import LinkButton from 'components/common/LinkButton'; import LinkButton from '@/components/common/LinkButton';
export function TeamsTable({ export function TeamsTable({
data = [], data = [],

View file

@ -1,6 +1,6 @@
import { Button, Icon, Text, Modal, Icons, ModalTrigger, useToasts } from 'react-basics'; import { Button, Icon, Text, Modal, Icons, ModalTrigger, useToasts } from 'react-basics';
import UserAddForm from './UserAddForm'; import UserAddForm from './UserAddForm';
import { useMessages, useModified } from 'components/hooks'; import { useMessages, useModified } from '@/components/hooks';
export function UserAddButton({ onSave }: { onSave?: () => void }) { export function UserAddButton({ onSave }: { onSave?: () => void }) {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();

View file

@ -10,8 +10,8 @@ import {
SubmitButton, SubmitButton,
Button, Button,
} from 'react-basics'; } from 'react-basics';
import { useApi, useMessages } from 'components/hooks'; import { useApi, useMessages } from '@/components/hooks';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
export function UserAddForm({ onSave, onClose }) { export function UserAddForm({ onSave, onClose }) {
const { post, useMutation } = useApi(); const { post, useMutation } = useApi();

View file

@ -1,5 +1,5 @@
import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics'; import { Button, Icon, Icons, Modal, ModalTrigger, Text } from 'react-basics';
import { useMessages, useLogin } from 'components/hooks'; import { useMessages, useLogin } from '@/components/hooks';
import UserDeleteForm from './UserDeleteForm'; import UserDeleteForm from './UserDeleteForm';
export function UserDeleteButton({ export function UserDeleteButton({

View file

@ -1,8 +1,8 @@
import { useApi, useMessages, useModified } from 'components/hooks'; import { useApi, useMessages, useModified } from '@/components/hooks';
import ConfirmationForm from 'components/common/ConfirmationForm'; import ConfirmationForm from '@/components/common/ConfirmationForm';
export function UserDeleteForm({ userId, username, onSave, onClose }) { export function UserDeleteForm({ userId, username, onSave, onClose }) {
const { FormattedMessage, messages, labels, formatMessage } = useMessages(); const { messages, labels, formatMessage } = useMessages();
const { del, useMutation } = useApi(); const { del, useMutation } = useApi();
const { mutate, error, isPending } = useMutation({ mutationFn: () => del(`/users/${userId}`) }); const { mutate, error, isPending } = useMutation({ mutationFn: () => del(`/users/${userId}`) });
const { touch } = useModified(); const { touch } = useModified();
@ -19,9 +19,7 @@ export function UserDeleteForm({ userId, username, onSave, onClose }) {
return ( return (
<ConfirmationForm <ConfirmationForm
message={ message={formatMessage(messages.confirmDelete, { target: <b>{username}</b> })}
<FormattedMessage {...messages.confirmDelete} values={{ target: <b>{username}</b> }} />
}
onConfirm={handleConfirm} onConfirm={handleConfirm}
onClose={onClose} onClose={onClose}
buttonLabel={formatMessage(labels.delete)} buttonLabel={formatMessage(labels.delete)}

View file

@ -1,5 +1,5 @@
import DataTable from 'components/common/DataTable'; import DataTable from '@/components/common/DataTable';
import { useUsers } from 'components/hooks'; import { useUsers } from '@/components/hooks';
import UsersTable from './UsersTable'; import UsersTable from './UsersTable';
import { ReactNode } from 'react'; import { ReactNode } from 'react';

View file

@ -1,5 +1,5 @@
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import UserAddButton from './UserAddButton'; import UserAddButton from './UserAddButton';
export function UsersHeader({ onAdd }: { onAdd?: () => void }) { export function UsersHeader({ onAdd }: { onAdd?: () => void }) {

View file

@ -1,9 +1,9 @@
import { Text, Icon, Icons, GridTable, GridColumn } from 'react-basics'; import { Text, Icon, Icons, GridTable, GridColumn } from 'react-basics';
import { formatDistance } from 'date-fns'; import { formatDistance } from 'date-fns';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
import { useMessages, useLocale } from 'components/hooks'; import { useMessages, useLocale } from '@/components/hooks';
import UserDeleteButton from './UserDeleteButton'; import UserDeleteButton from './UserDeleteButton';
import LinkButton from 'components/common/LinkButton'; import LinkButton from '@/components/common/LinkButton';
export function UsersTable({ export function UsersTable({
data = [], data = [],

View file

@ -9,8 +9,8 @@ import {
SubmitButton, SubmitButton,
PasswordField, PasswordField,
} from 'react-basics'; } from 'react-basics';
import { useApi, useLogin, useMessages } from 'components/hooks'; import { useApi, useLogin, useMessages } from '@/components/hooks';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
import { useContext, useRef } from 'react'; import { useContext, useRef } from 'react';
import { UserContext } from './UserProvider'; import { UserContext } from './UserProvider';

View file

@ -1,5 +1,5 @@
import { createContext, ReactNode, useEffect } from 'react'; import { createContext, ReactNode, useEffect } from 'react';
import { useModified, useUser } from 'components/hooks'; import { useModified, useUser } from '@/components/hooks';
import { Loading } from 'react-basics'; import { Loading } from 'react-basics';
export const UserContext = createContext(null); export const UserContext = createContext(null);

View file

@ -1,12 +1,12 @@
import { Key, useContext, useState } from 'react'; import { Key, useContext, useState } from 'react';
import { Item, Tabs, useToasts } from 'react-basics'; import { Item, Tabs, useToasts } from 'react-basics';
import Icons from 'components/icons'; import Icons from '@/components/icons';
import UserEditForm from './UserEditForm'; import UserEditForm from './UserEditForm';
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import UserWebsites from './UserWebsites'; import UserWebsites from './UserWebsites';
import { UserContext } from './UserProvider'; import { UserContext } from './UserProvider';
import Breadcrumb from 'components/common/Breadcrumb'; import Breadcrumb from '@/components/common/Breadcrumb';
export function UserSettings({ userId }: { userId: string }) { export function UserSettings({ userId }: { userId: string }) {
const { formatMessage, labels, messages } = useMessages(); const { formatMessage, labels, messages } = useMessages();

View file

@ -1,6 +1,6 @@
import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable'; import WebsitesTable from '@/app/(main)/settings/websites/WebsitesTable';
import DataTable from 'components/common/DataTable'; import DataTable from '@/components/common/DataTable';
import { useWebsites } from 'components/hooks'; import { useWebsites } from '@/components/hooks';
export function UserWebsites({ userId }) { export function UserWebsites({ userId }) {
const queryResult = useWebsites({ userId }); const queryResult = useWebsites({ userId });

View file

@ -1,4 +1,4 @@
import { useMessages, useModified } from 'components/hooks'; import { useMessages, useModified } from '@/components/hooks';
import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics'; import { Button, Icon, Icons, Modal, ModalTrigger, Text, useToasts } from 'react-basics';
import WebsiteAddForm from './WebsiteAddForm'; import WebsiteAddForm from './WebsiteAddForm';

View file

@ -7,9 +7,9 @@ import {
Button, Button,
SubmitButton, SubmitButton,
} from 'react-basics'; } from 'react-basics';
import { useApi } from 'components/hooks'; import { useApi } from '@/components/hooks';
import { DOMAIN_REGEX } from 'lib/constants'; import { DOMAIN_REGEX } from '@/lib/constants';
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
export function WebsiteAddForm({ export function WebsiteAddForm({
teamId, teamId,

View file

@ -1,7 +1,7 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import WebsitesTable from 'app/(main)/settings/websites/WebsitesTable'; import WebsitesTable from '@/app/(main)/settings/websites/WebsitesTable';
import DataTable from 'components/common/DataTable'; import DataTable from '@/components/common/DataTable';
import { useWebsites } from 'components/hooks'; import { useWebsites } from '@/components/hooks';
export function WebsitesDataTable({ export function WebsitesDataTable({
teamId, teamId,

View file

@ -1,5 +1,5 @@
import { useMessages } from 'components/hooks'; import { useMessages } from '@/components/hooks';
import PageHeader from 'components/layout/PageHeader'; import PageHeader from '@/components/layout/PageHeader';
import WebsiteAddButton from './WebsiteAddButton'; import WebsiteAddButton from './WebsiteAddButton';
export interface WebsitesHeaderProps { export interface WebsitesHeaderProps {

View file

@ -1,8 +1,8 @@
'use client'; 'use client';
import { useLogin } from 'components/hooks'; import { useLogin } from '@/components/hooks';
import WebsitesDataTable from './WebsitesDataTable'; import WebsitesDataTable from './WebsitesDataTable';
import WebsitesHeader from './WebsitesHeader'; import WebsitesHeader from './WebsitesHeader';
import { ROLES } from 'lib/constants'; import { ROLES } from '@/lib/constants';
export default function WebsitesSettingsPage({ teamId }: { teamId: string }) { export default function WebsitesSettingsPage({ teamId }: { teamId: string }) {
const { user } = useLogin(); const { user } = useLogin();

View file

@ -1,7 +1,7 @@
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { Text, Icon, Icons, GridTable, GridColumn } from 'react-basics'; import { Text, Icon, Icons, GridTable, GridColumn } from 'react-basics';
import { useMessages, useTeamUrl } from 'components/hooks'; import { useMessages, useTeamUrl } from '@/components/hooks';
import LinkButton from 'components/common/LinkButton'; import LinkButton from '@/components/common/LinkButton';
export interface WebsitesTableProps { export interface WebsitesTableProps {
data: any[]; data: any[];

Some files were not shown because too many files have changed in this diff Show more