mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-26 12:29:05 +01:00
Merge branch 'umami-software:dev' into dev
This commit is contained in:
commit
02db7185ec
@ -12,8 +12,8 @@ RUN yarn install --frozen-lockfile
|
|||||||
FROM node:18-alpine AS builder
|
FROM node:18-alpine AS builder
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=deps /app/node_modules ./node_modules
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
COPY docker/middleware.js .
|
|
||||||
COPY . .
|
COPY . .
|
||||||
|
COPY docker/middleware.js ./src
|
||||||
|
|
||||||
ARG DATABASE_TYPE
|
ARG DATABASE_TYPE
|
||||||
ARG BASE_PATH
|
ARG BASE_PATH
|
||||||
|
@ -10,7 +10,7 @@ A detailed getting started guide can be found at [https://umami.is/docs/](https:
|
|||||||
|
|
||||||
### Requirements
|
### Requirements
|
||||||
|
|
||||||
- A server with Node.js version 12 or newer
|
- A server with Node.js version 16.13 or newer
|
||||||
- A database. Umami supports [MySQL](https://www.mysql.com/) and [Postgresql](https://www.postgresql.org/) databases.
|
- A database. Umami supports [MySQL](https://www.mysql.com/) and [Postgresql](https://www.postgresql.org/) databases.
|
||||||
|
|
||||||
### Install Yarn
|
### Install Yarn
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "umami",
|
"name": "umami",
|
||||||
"version": "2.6.0",
|
"version": "2.6.2",
|
||||||
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
|
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
|
||||||
"author": "Mike Cao <mike@mikecao.com>",
|
"author": "Mike Cao <mike@mikecao.com>",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -104,7 +104,7 @@
|
|||||||
"label.browser": [
|
"label.browser": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Browser"
|
"value": "浏览器"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.browsers": [
|
"label.browsers": [
|
||||||
@ -134,7 +134,7 @@
|
|||||||
"label.city": [
|
"label.city": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "City"
|
"value": "市/县"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.clear-all": [
|
"label.clear-all": [
|
||||||
@ -176,7 +176,7 @@
|
|||||||
"label.country": [
|
"label.country": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Country"
|
"value": "国家/地区"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.create-report": [
|
"label.create-report": [
|
||||||
@ -230,7 +230,7 @@
|
|||||||
"label.date": [
|
"label.date": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Date"
|
"value": "日期"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.date-range": [
|
"label.date-range": [
|
||||||
@ -242,7 +242,7 @@
|
|||||||
"label.day": [
|
"label.day": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Day"
|
"value": "日"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.default-date-range": [
|
"label.default-date-range": [
|
||||||
@ -296,7 +296,7 @@
|
|||||||
"label.device": [
|
"label.device": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Device"
|
"value": "设备"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.devices": [
|
"label.devices": [
|
||||||
@ -440,13 +440,13 @@
|
|||||||
"label.is-not-set": [
|
"label.is-not-set": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Is not set"
|
"value": "未设置"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.is-set": [
|
"label.is-set": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Is set"
|
"value": "已设置"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.join": [
|
"label.join": [
|
||||||
@ -576,7 +576,7 @@
|
|||||||
"label.my-websites": [
|
"label.my-websites": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "My websites"
|
"value": "我的网站"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.name": [
|
"label.name": [
|
||||||
@ -618,7 +618,15 @@
|
|||||||
"label.page-of": [
|
"label.page-of": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Page "
|
"value": "总"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 1,
|
||||||
|
"value": "total"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": 0,
|
||||||
|
"value": "中的第"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": 1,
|
"type": 1,
|
||||||
@ -626,11 +634,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": " of "
|
"value": "页"
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"value": "total"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.page-views": [
|
"label.page-views": [
|
||||||
@ -642,7 +646,7 @@
|
|||||||
"label.pageTitle": [
|
"label.pageTitle": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Page title"
|
"value": "标题"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.pages": [
|
"label.pages": [
|
||||||
@ -704,7 +708,7 @@
|
|||||||
"label.referrer": [
|
"label.referrer": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Referrer"
|
"value": "来源"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.referrers": [
|
"label.referrers": [
|
||||||
@ -728,7 +732,7 @@
|
|||||||
"label.region": [
|
"label.region": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Region"
|
"value": "州/省"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.regions": [
|
"label.regions": [
|
||||||
@ -770,7 +774,7 @@
|
|||||||
"label.retention": [
|
"label.retention": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Retention"
|
"value": "保留"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.role": [
|
"label.role": [
|
||||||
@ -872,7 +876,7 @@
|
|||||||
"label.team-name": [
|
"label.team-name": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Team name"
|
"value": "团队名称"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.team-owner": [
|
"label.team-owner": [
|
||||||
@ -884,7 +888,7 @@
|
|||||||
"label.team-websites": [
|
"label.team-websites": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Team websites"
|
"value": "团队网站"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.teams": [
|
"label.teams": [
|
||||||
@ -974,7 +978,7 @@
|
|||||||
"label.unique": [
|
"label.unique": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Unique"
|
"value": "独立"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.unique-visitors": [
|
"label.unique-visitors": [
|
||||||
@ -998,13 +1002,13 @@
|
|||||||
"label.url": [
|
"label.url": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "URL"
|
"value": "网址"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.urls": [
|
"label.urls": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "URLs"
|
"value": "网址"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.user": [
|
"label.user": [
|
||||||
@ -1046,7 +1050,7 @@
|
|||||||
"label.view-only": [
|
"label.view-only": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "View only"
|
"value": "仅浏览量"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.views": [
|
"label.views": [
|
||||||
@ -1190,15 +1194,15 @@
|
|||||||
"message.event-log": [
|
"message.event-log": [
|
||||||
{
|
{
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"value": "event"
|
"value": "url"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": " on "
|
"value": "上的"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": 1,
|
"type": 1,
|
||||||
"value": "url"
|
"value": "event"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"message.go-to-settings": [
|
"message.go-to-settings": [
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useCallback, useState } from 'react';
|
import { useEffect, useCallback, useState } from 'react';
|
||||||
|
import { createPortal } from 'react-dom';
|
||||||
import { Button, Row, Column } from 'react-basics';
|
import { Button, Row, Column } from 'react-basics';
|
||||||
import { setItem } from 'next-basics';
|
import { setItem } from 'next-basics';
|
||||||
import useStore, { checkVersion } from 'store/version';
|
import useStore, { checkVersion } from 'store/version';
|
||||||
@ -44,7 +45,7 @@ export function UpdateNotice({ user, config }) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return createPortal(
|
||||||
<Row className={styles.notice}>
|
<Row className={styles.notice}>
|
||||||
<Column variant="two" className={styles.message}>
|
<Column variant="two" className={styles.message}>
|
||||||
{formatMessage(messages.newVersionAvailable, { version: `v${latest}` })}
|
{formatMessage(messages.newVersionAvailable, { version: `v${latest}` })}
|
||||||
@ -55,7 +56,8 @@ export function UpdateNotice({ user, config }) {
|
|||||||
</Button>
|
</Button>
|
||||||
<Button onClick={handleDismissClick}>{formatMessage(labels.dismiss)}</Button>
|
<Button onClick={handleDismissClick}>{formatMessage(labels.dismiss)}</Button>
|
||||||
</Column>
|
</Column>
|
||||||
</Row>
|
</Row>,
|
||||||
|
document.body,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,13 +2,14 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
max-width: 800px;
|
max-width: 800px;
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
margin: 20px auto;
|
margin: 80px auto;
|
||||||
justify-self: center;
|
align-self: center;
|
||||||
background: var(--base50);
|
background: var(--base50);
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
border: 1px solid var(--base300);
|
border: 1px solid var(--base300);
|
||||||
border-radius: var(--border-radius);
|
border-radius: var(--border-radius);
|
||||||
z-index: var(--z-index-popup);
|
z-index: var(--z-index-popup);
|
||||||
|
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.message {
|
.message {
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { useState } from 'react';
|
import { Button, Icon, Icons, Text } from 'react-basics';
|
||||||
import { Button, Icon, Icons, Text, Flexbox } from 'react-basics';
|
|
||||||
import Link from 'next/link';
|
import Link from 'next/link';
|
||||||
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 Pager from 'components/common/Pager';
|
||||||
import WebsiteChartList from 'components/pages/websites/WebsiteChartList';
|
import WebsiteChartList from 'components/pages/websites/WebsiteChartList';
|
||||||
import DashboardSettingsButton from 'components/pages/dashboard/DashboardSettingsButton';
|
import DashboardSettingsButton from 'components/pages/dashboard/DashboardSettingsButton';
|
||||||
import DashboardEdit from 'components/pages/dashboard/DashboardEdit';
|
import DashboardEdit from 'components/pages/dashboard/DashboardEdit';
|
||||||
@ -11,23 +11,24 @@ import useApi from 'components/hooks/useApi';
|
|||||||
import useDashboard from 'store/dashboard';
|
import useDashboard from 'store/dashboard';
|
||||||
import useMessages from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
import useLocale from 'components/hooks/useLocale';
|
import useLocale from 'components/hooks/useLocale';
|
||||||
|
import useApiFilter from 'components/hooks/useApiFilter';
|
||||||
|
|
||||||
export function Dashboard() {
|
export function Dashboard() {
|
||||||
const { formatMessage, labels, messages } = useMessages();
|
const { formatMessage, labels, messages } = useMessages();
|
||||||
const dashboard = useDashboard();
|
const { showCharts, editing } = useDashboard();
|
||||||
const { showCharts, limit, editing } = dashboard;
|
|
||||||
const [max, setMax] = useState(limit);
|
|
||||||
const { get, useQuery } = useApi();
|
|
||||||
const { data, isLoading, error } = useQuery(['websites'], () =>
|
|
||||||
get('/websites', { includeTeams: 1 }),
|
|
||||||
);
|
|
||||||
const hasData = data && data?.data.length !== 0;
|
|
||||||
|
|
||||||
const { dir } = useLocale();
|
const { dir } = useLocale();
|
||||||
|
const { get, useQuery } = useApi();
|
||||||
function handleMore() {
|
const { page, handlePageChange } = useApiFilter();
|
||||||
setMax(max + limit);
|
const pageSize = 10;
|
||||||
}
|
const {
|
||||||
|
data: result,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
} = useQuery(['websites', page, pageSize], () =>
|
||||||
|
get('/websites', { includeTeams: 1, page, pageSize }),
|
||||||
|
);
|
||||||
|
const { data, count } = result || {};
|
||||||
|
const hasData = data && data?.length !== 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page loading={isLoading} error={error}>
|
<Page loading={isLoading} error={error}>
|
||||||
@ -48,19 +49,17 @@ export function Dashboard() {
|
|||||||
)}
|
)}
|
||||||
{hasData && (
|
{hasData && (
|
||||||
<>
|
<>
|
||||||
{editing && <DashboardEdit websites={data?.data} />}
|
{editing && <DashboardEdit />}
|
||||||
{!editing && (
|
{!editing && (
|
||||||
<WebsiteChartList websites={data?.data} showCharts={showCharts} limit={max} />
|
<>
|
||||||
)}
|
<WebsiteChartList websites={data} showCharts={showCharts} limit={pageSize} />
|
||||||
{max < data.length && (
|
<Pager
|
||||||
<Flexbox justifyContent="center">
|
page={page}
|
||||||
<Button onClick={handleMore}>
|
pageSize={pageSize}
|
||||||
<Icon rotate={dir === 'rtl' ? 180 : 0}>
|
count={count}
|
||||||
<Icons.More />
|
onPageChange={handlePageChange}
|
||||||
</Icon>
|
/>
|
||||||
<Text>{formatMessage(labels.more)}</Text>
|
</>
|
||||||
</Button>
|
|
||||||
</Flexbox>
|
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
@ -5,23 +5,33 @@ import { Button } 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 from 'components/hooks/useMessages';
|
import useMessages from 'components/hooks/useMessages';
|
||||||
|
import useApi from 'components/hooks/useApi';
|
||||||
import styles from './DashboardEdit.module.css';
|
import styles from './DashboardEdit.module.css';
|
||||||
|
import Page from 'components/layout/Page';
|
||||||
|
|
||||||
const dragId = 'dashboard-website-ordering';
|
const dragId = 'dashboard-website-ordering';
|
||||||
|
|
||||||
export function DashboardEdit({ websites }) {
|
export function DashboardEdit() {
|
||||||
const settings = useDashboard();
|
const settings = useDashboard();
|
||||||
const { websiteOrder } = settings;
|
const { websiteOrder } = settings;
|
||||||
const { formatMessage, labels } = useMessages();
|
const { formatMessage, labels } = useMessages();
|
||||||
const [order, setOrder] = useState(websiteOrder || []);
|
const [order, setOrder] = useState(websiteOrder || []);
|
||||||
|
const { get, useQuery } = useApi();
|
||||||
|
const {
|
||||||
|
data: result,
|
||||||
|
isLoading,
|
||||||
|
error,
|
||||||
|
} = useQuery(['websites'], () => get('/websites', { includeTeams: 1 }));
|
||||||
|
const { data: websites } = result || {};
|
||||||
|
|
||||||
const ordered = useMemo(
|
const ordered = useMemo(() => {
|
||||||
() =>
|
if (websites) {
|
||||||
websites
|
return websites
|
||||||
.map(website => ({ ...website, order: order.indexOf(website.id) }))
|
.map(website => ({ ...website, order: order.indexOf(website.id) }))
|
||||||
.sort(firstBy('order')),
|
.sort(firstBy('order'));
|
||||||
[websites, order],
|
}
|
||||||
);
|
return [];
|
||||||
|
}, [websites, order]);
|
||||||
|
|
||||||
function handleWebsiteDrag({ destination, source }) {
|
function handleWebsiteDrag({ destination, source }) {
|
||||||
if (!destination || destination.index === source.index) return;
|
if (!destination || destination.index === source.index) return;
|
||||||
@ -49,7 +59,7 @@ export function DashboardEdit({ websites }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<Page loading={isLoading} error={error}>
|
||||||
<div className={styles.buttons}>
|
<div className={styles.buttons}>
|
||||||
<Button onClick={handleSave} variant="action" size="small">
|
<Button onClick={handleSave} variant="action" size="small">
|
||||||
{formatMessage(labels.save)}
|
{formatMessage(labels.save)}
|
||||||
@ -95,7 +105,7 @@ export function DashboardEdit({ websites }) {
|
|||||||
</Droppable>
|
</Droppable>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</Page>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,211 +1,211 @@
|
|||||||
{
|
{
|
||||||
"label.access-code": "Access code",
|
"label.access-code": "Koda za dostop",
|
||||||
"label.actions": "Dejanja",
|
"label.actions": "Dejanja",
|
||||||
"label.activity-log": "Activity log",
|
"label.activity-log": "Dnevnik dejavnosti",
|
||||||
"label.add": "Add",
|
"label.add": "Dodaj",
|
||||||
"label.add-description": "Add description",
|
"label.add-description": "Dodaj opis",
|
||||||
"label.add-website": "Dodaj spletno mesto",
|
"label.add-website": "Dodaj spletno mesto",
|
||||||
"label.admin": "Administrator",
|
"label.admin": "Administrator",
|
||||||
"label.after": "After",
|
"label.after": "Po",
|
||||||
"label.all": "Vse",
|
"label.all": "Vsi",
|
||||||
"label.all-time": "All time",
|
"label.all-time": "Ves čas",
|
||||||
"label.analytics": "Analytics",
|
"label.analytics": "Analitika",
|
||||||
"label.average": "Average",
|
"label.average": "Povprečno",
|
||||||
"label.average-visit-time": "Povprečni čas obiska",
|
"label.average-visit-time": "Povprečni čas obiska",
|
||||||
"label.back": "Nazaj",
|
"label.back": "Nazaj",
|
||||||
"label.before": "Before",
|
"label.before": "Pred",
|
||||||
"label.bounce-rate": "Zapustna stopnja",
|
"label.bounce-rate": "Odbojna stopnja",
|
||||||
"label.breakdown": "Breakdown",
|
"label.breakdown": "Razčlenitev",
|
||||||
"label.browser": "Browser",
|
"label.browser": "Brskalnik",
|
||||||
"label.browsers": "Brskalniki",
|
"label.browsers": "Brskalniki",
|
||||||
"label.cancel": "Prekliči",
|
"label.cancel": "Prekliči",
|
||||||
"label.change-password": "Zamenjaj geslo",
|
"label.change-password": "Zamenjaj geslo",
|
||||||
"label.cities": "Cities",
|
"label.cities": "Mesta",
|
||||||
"label.city": "City",
|
"label.city": "Mesto",
|
||||||
"label.clear-all": "Clear all",
|
"label.clear-all": "Počisti vse",
|
||||||
"label.confirm": "Confirm",
|
"label.confirm": "Potrdi",
|
||||||
"label.confirm-password": "Potrditev gesla",
|
"label.confirm-password": "Potrdi geslo",
|
||||||
"label.contains": "Contains",
|
"label.contains": "Vsebuje",
|
||||||
"label.continue": "Continue",
|
"label.continue": "Nadaljuj",
|
||||||
"label.countries": "Države",
|
"label.countries": "Države",
|
||||||
"label.country": "Country",
|
"label.country": "Država",
|
||||||
"label.create-report": "Create report",
|
"label.create-report": "Ustvari poročilo",
|
||||||
"label.create-team": "Create team",
|
"label.create-team": "Ustvari ekipo",
|
||||||
"label.create-user": "Create user",
|
"label.create-user": "Ustvari uporabnika",
|
||||||
"label.created": "Created",
|
"label.created": "Ustvarjeno",
|
||||||
"label.current-password": "Trenutno geslo",
|
"label.current-password": "Trenutno geslo",
|
||||||
"label.custom-range": "Razpon po meri",
|
"label.custom-range": "Obdobje po meri",
|
||||||
"label.dashboard": "Nadzorna plošča",
|
"label.dashboard": "Nadzorna plošča",
|
||||||
"label.data": "Data",
|
"label.data": "Podatki",
|
||||||
"label.date": "Date",
|
"label.date": "Datum",
|
||||||
"label.date-range": "Časovni razpon",
|
"label.date-range": "Časovno obdobje",
|
||||||
"label.day": "Day",
|
"label.day": "Dan",
|
||||||
"label.default-date-range": "Privzeti časovni razpon",
|
"label.default-date-range": "Privzeto časovno obdobje",
|
||||||
"label.delete": "Izbriši",
|
"label.delete": "Izbriši",
|
||||||
"label.delete-team": "Delete team",
|
"label.delete-team": "Izbriši ekipo",
|
||||||
"label.delete-user": "Delete user",
|
"label.delete-user": "Izbriši uporabnika",
|
||||||
"label.delete-website": "Izbriši spletno mesto",
|
"label.delete-website": "Izbriši spletno mesto",
|
||||||
"label.description": "Description",
|
"label.description": "Opis",
|
||||||
"label.desktop": "Namizni računalnik",
|
"label.desktop": "Namizni računalnik",
|
||||||
"label.details": "Details",
|
"label.details": "Podrobnosti",
|
||||||
"label.device": "Device",
|
"label.device": "Naprava",
|
||||||
"label.devices": "Naprave",
|
"label.devices": "Naprave",
|
||||||
"label.dismiss": "Opusti",
|
"label.dismiss": "Prezri",
|
||||||
"label.does-not-contain": "Does not contain",
|
"label.does-not-contain": "Ne vsebuje",
|
||||||
"label.domain": "Domena",
|
"label.domain": "Domena",
|
||||||
"label.dropoff": "Dropoff",
|
"label.dropoff": "Zapustitev",
|
||||||
"label.edit": "Uredi",
|
"label.edit": "Uredi",
|
||||||
"label.edit-dashboard": "Edit dashboard",
|
"label.edit-dashboard": "Uredi nadzorno ploščo",
|
||||||
"label.enable-share-url": "Omogoči URL za skupno rabo",
|
"label.enable-share-url": "Uredi povezavo za deljenje",
|
||||||
"label.event": "Event",
|
"label.event": "Dogodek",
|
||||||
"label.event-data": "Event data",
|
"label.event-data": "Podatki dogodka",
|
||||||
"label.events": "Dogodki",
|
"label.events": "Dogodki",
|
||||||
"label.false": "False",
|
"label.false": "Napačno",
|
||||||
"label.field": "Field",
|
"label.field": "Polje",
|
||||||
"label.fields": "Fields",
|
"label.fields": "Polja",
|
||||||
"label.filter-combined": "Skupno",
|
"label.filter-combined": "Skupaj",
|
||||||
"label.filter-raw": "Neobdelane meritve",
|
"label.filter-raw": "Neobdelano",
|
||||||
"label.filters": "Filters",
|
"label.filters": "Filtri",
|
||||||
"label.funnel": "Funnel",
|
"label.funnel": "Prodajni lijak",
|
||||||
"label.greater-than": "Greater than",
|
"label.greater-than": "Večje od",
|
||||||
"label.greater-than-equals": "Greater than or equals",
|
"label.greater-than-equals": "Večje ali enako kot",
|
||||||
"label.insights": "Insights",
|
"label.insights": "Vpogled",
|
||||||
"label.is": "Is",
|
"label.is": "Je",
|
||||||
"label.is-not": "Is not",
|
"label.is-not": "Ni",
|
||||||
"label.is-not-set": "Is not set",
|
"label.is-not-set": "Ni nastavljeno",
|
||||||
"label.is-set": "Is set",
|
"label.is-set": "Je nastavljeno",
|
||||||
"label.join": "Join",
|
"label.join": "Pridruži se",
|
||||||
"label.join-team": "Join team",
|
"label.join-team": "Pridruži se ekipi",
|
||||||
"label.language": "Language",
|
"label.language": "Jezik",
|
||||||
"label.languages": "Languages",
|
"label.languages": "Jeziki",
|
||||||
"label.laptop": "Prenosni računalnik",
|
"label.laptop": "Prenosni računalnik",
|
||||||
"label.last-days": "Zadnjih {x} dni",
|
"label.last-days": "Zadnjih {x} dni",
|
||||||
"label.last-hours": "Zadnjih {x} ur",
|
"label.last-hours": "Zadnjih {x} ur",
|
||||||
"label.leave": "Leave",
|
"label.leave": "Zapusti",
|
||||||
"label.leave-team": "Leave team",
|
"label.leave-team": "Zapusti ekipo",
|
||||||
"label.less-than": "Less than",
|
"label.less-than": "Manjše kot",
|
||||||
"label.less-than-equals": "Less than or equals",
|
"label.less-than-equals": "Manjše ali enako kot",
|
||||||
"label.login": "Prijava",
|
"label.login": "Prijava",
|
||||||
"label.logout": "Odjava",
|
"label.logout": "Odjava",
|
||||||
"label.max": "Max",
|
"label.max": "Največ",
|
||||||
"label.members": "Members",
|
"label.members": "Člani",
|
||||||
"label.min": "Min",
|
"label.min": "Najmanj",
|
||||||
"label.mobile": "Mobilni telefon",
|
"label.mobile": "Mobilne naprave",
|
||||||
"label.more": "Več",
|
"label.more": "Več",
|
||||||
"label.my-websites": "My websites",
|
"label.my-websites": "Moja spletna mesta",
|
||||||
"label.name": "Ime",
|
"label.name": "Ime",
|
||||||
"label.new-password": "Novo geslo",
|
"label.new-password": "Novo geslo",
|
||||||
"label.none": "None",
|
"label.none": "Brez",
|
||||||
"label.os": "OS",
|
"label.os": "OS",
|
||||||
"label.overview": "Overview",
|
"label.overview": "Pregled",
|
||||||
"label.owner": "Owner",
|
"label.owner": "Lastnik",
|
||||||
"label.page-of": "Page {current} of {total}",
|
"label.page-of": "Stran {current} od {total}",
|
||||||
"label.page-views": "Ogledi strani",
|
"label.page-views": "Obiski strani",
|
||||||
"label.pageTitle": "Page title",
|
"label.pageTitle": "Naslov strani",
|
||||||
"label.pages": "Strani",
|
"label.pages": "Strani",
|
||||||
"label.password": "Geslo",
|
"label.password": "Geslo",
|
||||||
"label.powered-by": "Zagotavlja {name}",
|
"label.powered-by": "Poganja {name}",
|
||||||
"label.profile": "Profil",
|
"label.profile": "Profil",
|
||||||
"label.queries": "Queries",
|
"label.queries": "Poizvedbe",
|
||||||
"label.query": "Query",
|
"label.query": "Poizvedba",
|
||||||
"label.query-parameters": "Query parameters",
|
"label.query-parameters": "Parametri poizvedbe",
|
||||||
"label.realtime": "V realnem času",
|
"label.realtime": "V živo",
|
||||||
"label.referrer": "Referrer",
|
"label.referrer": "Vir",
|
||||||
"label.referrers": "Viri",
|
"label.referrers": "Viri",
|
||||||
"label.refresh": "Osveži",
|
"label.refresh": "Osveži",
|
||||||
"label.regenerate": "Regenerate",
|
"label.regenerate": "Ponovno generiraj",
|
||||||
"label.region": "Region",
|
"label.region": "Regija",
|
||||||
"label.regions": "Regions",
|
"label.regions": "Regije",
|
||||||
"label.remove": "Remove",
|
"label.remove": "Odstrani",
|
||||||
"label.reports": "Reports",
|
"label.reports": "Poročila",
|
||||||
"label.required": "Zahtevano",
|
"label.required": "Zahtevano",
|
||||||
"label.reset": "Ponastavi",
|
"label.reset": "Ponastavi",
|
||||||
"label.reset-website": "Reset statistics",
|
"label.reset-website": "Ponastavi statistiko",
|
||||||
"label.retention": "Retention",
|
"label.retention": "Ohranjanje uporabnikov",
|
||||||
"label.role": "Role",
|
"label.role": "Vloga",
|
||||||
"label.run-query": "Run query",
|
"label.run-query": "Izvedi poizvedbo",
|
||||||
"label.save": "Shrani",
|
"label.save": "Shrani",
|
||||||
"label.screens": "Screens",
|
"label.screens": "Zasloni",
|
||||||
"label.select-date": "Select date",
|
"label.select-date": "Izberi datum",
|
||||||
"label.select-website": "Select website",
|
"label.select-website": "Izberi spletno mesto",
|
||||||
"label.sessions": "Sessions",
|
"label.sessions": "Seje",
|
||||||
"label.settings": "Nastavitve",
|
"label.settings": "Nastavitve",
|
||||||
"label.share-url": "Deli URL",
|
"label.share-url": "Deli povezavo",
|
||||||
"label.single-day": "En dan",
|
"label.single-day": "En dan",
|
||||||
"label.sum": "Sum",
|
"label.sum": "Seštevek",
|
||||||
"label.tablet": "Tablični računalnik",
|
"label.tablet": "Tablični računalnik",
|
||||||
"label.team": "Team",
|
"label.team": "Ekipa",
|
||||||
"label.team-guest": "Team guest",
|
"label.team-guest": "Gost ekipe",
|
||||||
"label.team-id": "Team ID",
|
"label.team-id": "ID ekipe",
|
||||||
"label.team-member": "Team member",
|
"label.team-member": "Član ekipe",
|
||||||
"label.team-name": "Team name",
|
"label.team-name": "Ime ekipe",
|
||||||
"label.team-owner": "Team owner",
|
"label.team-owner": "Lastnik ekipe",
|
||||||
"label.team-websites": "Team websites",
|
"label.team-websites": "Spletna mesta ekipe",
|
||||||
"label.teams": "Teams",
|
"label.teams": "Ekipe",
|
||||||
"label.theme": "Theme",
|
"label.theme": "Tema",
|
||||||
"label.this-month": "Ta mesec",
|
"label.this-month": "Ta mesec",
|
||||||
"label.this-week": "Ta teden",
|
"label.this-week": "Ta teden",
|
||||||
"label.this-year": "Letos",
|
"label.this-year": "To leto",
|
||||||
"label.timezone": "Časovni pas",
|
"label.timezone": "Časovni pas",
|
||||||
"label.title": "Title",
|
"label.title": "Naslov",
|
||||||
"label.today": "Danes",
|
"label.today": "Danes",
|
||||||
"label.toggle-charts": "Toggle charts",
|
"label.toggle-charts": "Preklopi grafe",
|
||||||
"label.total": "Total",
|
"label.total": "Skupaj",
|
||||||
"label.total-records": "Total records",
|
"label.total-records": "Skupni zapisi",
|
||||||
"label.tracking-code": "Koda za sledenje",
|
"label.tracking-code": "Koda za sledenje",
|
||||||
"label.true": "True",
|
"label.true": "Pravilno",
|
||||||
"label.type": "Type",
|
"label.type": "Vrsta",
|
||||||
"label.unique": "Unique",
|
"label.unique": "Unikatni",
|
||||||
"label.unique-visitors": "Unikatni obiskovalci",
|
"label.unique-visitors": "Unikatni obiskovalci",
|
||||||
"label.unknown": "Neznano",
|
"label.unknown": "Neznano",
|
||||||
"label.untitled": "Untitled",
|
"label.untitled": "Brez naslova",
|
||||||
"label.url": "URL",
|
"label.url": "Povezava",
|
||||||
"label.urls": "URLs",
|
"label.urls": "Povezave",
|
||||||
"label.user": "User",
|
"label.user": "Uporabnik",
|
||||||
"label.username": "Uporabniško ime",
|
"label.username": "Uporabniško ime",
|
||||||
"label.users": "Users",
|
"label.users": "Uporabniki",
|
||||||
"label.value": "Value",
|
"label.value": "Vrednost",
|
||||||
"label.view": "View",
|
"label.view": "Poglej",
|
||||||
"label.view-details": "Prikaži podrobnosti",
|
"label.view-details": "Poglej podrobnosti",
|
||||||
"label.view-only": "View only",
|
"label.view-only": "Samo ogledovanje",
|
||||||
"label.views": "Ogledi",
|
"label.views": "Obiski",
|
||||||
"label.visitors": "Obiskovalci",
|
"label.visitors": "Obiskovalci",
|
||||||
"label.website": "Website",
|
"label.website": "Spletno mesto",
|
||||||
"label.website-id": "Website ID",
|
"label.website-id": "ID spletnega mesta",
|
||||||
"label.websites": "Spletna mesta",
|
"label.websites": "Spletnih mest",
|
||||||
"label.window": "Window",
|
"label.window": "Okno",
|
||||||
"label.yesterday": "Yesterday",
|
"label.yesterday": "Včeraj",
|
||||||
"message.active-users": "{x} trenutni {x, plural, one {obiskovalec} other {obiskovalcev}}",
|
"message.active-users": "{x} trenutni {x, plural, one {obiskovalec} other {obiskovalcev}}",
|
||||||
"message.confirm-delete": "Ste prepričani, da želite izbrisati {target}?",
|
"message.confirm-delete": "Ste prepričani, da želite izbrisati {target}?",
|
||||||
"message.confirm-leave": "Are you sure you want to leave {target}?",
|
"message.confirm-leave": "Ste prepričani, da želite zapustiti {target}?",
|
||||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
"message.confirm-reset": "Ste prepričani, da želite ponastaviti statistiko {target}?",
|
||||||
"message.delete-account": "To delete this account, type {confirmation} in the box below to confirm.",
|
"message.delete-account": "Za potrditev izbrisa tega računa vnesite {confirmation} v spodnje polje.",
|
||||||
"message.delete-website": "To delete this website, type {confirmation} in the box below to confirm.",
|
"message.delete-website": "Za potrditev izbrisa tega spletnega mesta vnesite {confirmation} v spodnje polje.",
|
||||||
"message.delete-website-warning": "Izbrisani bodo tudi vsi povezani podatki.",
|
"message.delete-website-warning": "Izbrisani bodo tudi vsi pripadajoči podatki.",
|
||||||
"message.error": "Prišlo je do napake.",
|
"message.error": "Nekaj je šlo narobe.",
|
||||||
"message.event-log": "{event} on {url}",
|
"message.event-log": "{event} na {url}",
|
||||||
"message.go-to-settings": "Pojdi v nastavitve",
|
"message.go-to-settings": "Pojdi v nastavitve",
|
||||||
"message.incorrect-username-password": "Nepravilno uporabniško ime/geslo",
|
"message.incorrect-username-password": "Nepravilno uporabniško ime/geslo.",
|
||||||
"message.invalid-domain": "Neveljavna domena",
|
"message.invalid-domain": "Neveljavna domena",
|
||||||
"message.min-password-length": "Minimum length of {n} characters",
|
"message.min-password-length": "Najmanjša dolžina je {n} znakov",
|
||||||
"message.new-version-available": "A new version of Umami {version} is available!",
|
"message.new-version-available": "Na voljo je nova verzija programa Umami {version}!",
|
||||||
"message.no-data-available": "Podatki niso na voljo.",
|
"message.no-data-available": "Podatki niso na voljo.",
|
||||||
"message.no-event-data": "No event data is available.",
|
"message.no-event-data": "Podatki o dogodku niso na voljo.",
|
||||||
"message.no-match-password": "Gesli se ne ujemata",
|
"message.no-match-password": "Gesli se ne ujemata",
|
||||||
"message.no-results-found": "No results were found.",
|
"message.no-results-found": "Rezultatov ni bilo mogoče najti.",
|
||||||
"message.no-team-websites": "This team does not have any websites.",
|
"message.no-team-websites": "Ta ekipa nima spletnih mest.",
|
||||||
"message.no-teams": "You have not created any teams.",
|
"message.no-teams": "Niste še ustvarili nobene ekipe.",
|
||||||
"message.no-users": "There are no users.",
|
"message.no-users": "Ni uporabnikov.",
|
||||||
"message.no-websites-configured": "Ni nastavljenih spletnih mest.",
|
"message.no-websites-configured": "Nimate nastavljenih nobenih spletnih mest.",
|
||||||
"message.page-not-found": "Stran ni bila najdena.",
|
"message.page-not-found": "Stran ni bila najdena.",
|
||||||
"message.reset-website": "To reset this website, type {confirmation} in the box below to confirm.",
|
"message.reset-website": "Za ponastavitev izbrisa tega spletnega mesta vnesite {confirmation} v spodnje polje.",
|
||||||
"message.reset-website-warning": "All statistics for this website will be deleted, but your tracking code will remain intact.",
|
"message.reset-website-warning": "Vse statistike za to spletno mesto bodo izbrisane, koda za sledenje pa bo ostala nespremenjena.",
|
||||||
"message.saved": "Uspešno shranjeno.",
|
"message.saved": "Uspešno shranjeno.",
|
||||||
"message.share-url": "To je javno dostopen naslov URL za {target}.",
|
"message.share-url": "To je javno dostopna povezava za {target}.",
|
||||||
"message.team-already-member": "You are already a member of the team.",
|
"message.team-already-member": "Ste že član ekipe.",
|
||||||
"message.team-not-found": "Team not found.",
|
"message.team-not-found": "Ekipa ni bila najdena.",
|
||||||
"message.team-websites-info": "Websites can be viewed by anyone on the team.",
|
"message.team-websites-info": "Spletne strani si lahko ogleda vsak član ekipe.",
|
||||||
"message.tracking-code": "Koda za sledenje",
|
"message.tracking-code": "Koda za sledenje",
|
||||||
"message.user-deleted": "User deleted.",
|
"message.user-deleted": "Uporabnik je izbrisan.",
|
||||||
"message.visitor-log": "Obiskovalec iz {country} uporablja {browser} na {os} {device}"
|
"message.visitor-log": "Obiskovalec iz {country} uporablja {browser} na {os} {device}"
|
||||||
}
|
}
|
||||||
|
@ -16,19 +16,19 @@
|
|||||||
"label.before": "之前",
|
"label.before": "之前",
|
||||||
"label.bounce-rate": "跳出率",
|
"label.bounce-rate": "跳出率",
|
||||||
"label.breakdown": "故障",
|
"label.breakdown": "故障",
|
||||||
"label.browser": "Browser",
|
"label.browser": "浏览器",
|
||||||
"label.browsers": "浏览器",
|
"label.browsers": "浏览器",
|
||||||
"label.cancel": "取消",
|
"label.cancel": "取消",
|
||||||
"label.change-password": "更新密码",
|
"label.change-password": "更新密码",
|
||||||
"label.cities": "市/县",
|
"label.cities": "市/县",
|
||||||
"label.city": "City",
|
"label.city": "市/县",
|
||||||
"label.clear-all": "清除全部",
|
"label.clear-all": "清除全部",
|
||||||
"label.confirm": "确认",
|
"label.confirm": "确认",
|
||||||
"label.confirm-password": "确认密码",
|
"label.confirm-password": "确认密码",
|
||||||
"label.contains": "包含",
|
"label.contains": "包含",
|
||||||
"label.continue": "继续",
|
"label.continue": "继续",
|
||||||
"label.countries": "国家/地区",
|
"label.countries": "国家/地区",
|
||||||
"label.country": "Country",
|
"label.country": "国家/地区",
|
||||||
"label.create-report": "创建报告",
|
"label.create-report": "创建报告",
|
||||||
"label.create-team": "创建团队",
|
"label.create-team": "创建团队",
|
||||||
"label.create-user": "创建用户",
|
"label.create-user": "创建用户",
|
||||||
@ -37,9 +37,9 @@
|
|||||||
"label.custom-range": "自定义时间段",
|
"label.custom-range": "自定义时间段",
|
||||||
"label.dashboard": "仪表板",
|
"label.dashboard": "仪表板",
|
||||||
"label.data": "统计数据",
|
"label.data": "统计数据",
|
||||||
"label.date": "Date",
|
"label.date": "日期",
|
||||||
"label.date-range": "时间段",
|
"label.date-range": "时间段",
|
||||||
"label.day": "Day",
|
"label.day": "日",
|
||||||
"label.default-date-range": "默认时间段",
|
"label.default-date-range": "默认时间段",
|
||||||
"label.delete": "删除",
|
"label.delete": "删除",
|
||||||
"label.delete-team": "删除团队",
|
"label.delete-team": "删除团队",
|
||||||
@ -48,7 +48,7 @@
|
|||||||
"label.description": "描述",
|
"label.description": "描述",
|
||||||
"label.desktop": "台式机",
|
"label.desktop": "台式机",
|
||||||
"label.details": "详细信息",
|
"label.details": "详细信息",
|
||||||
"label.device": "Device",
|
"label.device": "设备",
|
||||||
"label.devices": "设备",
|
"label.devices": "设备",
|
||||||
"label.dismiss": "关闭",
|
"label.dismiss": "关闭",
|
||||||
"label.does-not-contain": "不包含",
|
"label.does-not-contain": "不包含",
|
||||||
@ -72,8 +72,8 @@
|
|||||||
"label.insights": "见解",
|
"label.insights": "见解",
|
||||||
"label.is": "等于",
|
"label.is": "等于",
|
||||||
"label.is-not": "不等于",
|
"label.is-not": "不等于",
|
||||||
"label.is-not-set": "Is not set",
|
"label.is-not-set": "未设置",
|
||||||
"label.is-set": "Is set",
|
"label.is-set": "已设置",
|
||||||
"label.join": "加入",
|
"label.join": "加入",
|
||||||
"label.join-team": "加入团队",
|
"label.join-team": "加入团队",
|
||||||
"label.language": "语言",
|
"label.language": "语言",
|
||||||
@ -92,16 +92,16 @@
|
|||||||
"label.min": "最小",
|
"label.min": "最小",
|
||||||
"label.mobile": "手机",
|
"label.mobile": "手机",
|
||||||
"label.more": "更多",
|
"label.more": "更多",
|
||||||
"label.my-websites": "My websites",
|
"label.my-websites": "我的网站",
|
||||||
"label.name": "名字",
|
"label.name": "名字",
|
||||||
"label.new-password": "新密码",
|
"label.new-password": "新密码",
|
||||||
"label.none": "无",
|
"label.none": "无",
|
||||||
"label.os": "OS",
|
"label.os": "OS",
|
||||||
"label.overview": "概览",
|
"label.overview": "概览",
|
||||||
"label.owner": "所有者",
|
"label.owner": "所有者",
|
||||||
"label.page-of": "Page {current} of {total}",
|
"label.page-of": "总{total}中的第{current}页",
|
||||||
"label.page-views": "页面浏览量",
|
"label.page-views": "页面浏览量",
|
||||||
"label.pageTitle": "Page title",
|
"label.pageTitle": "标题",
|
||||||
"label.pages": "网页",
|
"label.pages": "网页",
|
||||||
"label.password": "密码",
|
"label.password": "密码",
|
||||||
"label.powered-by": "由 {name} 提供支持",
|
"label.powered-by": "由 {name} 提供支持",
|
||||||
@ -110,18 +110,18 @@
|
|||||||
"label.query": "查询",
|
"label.query": "查询",
|
||||||
"label.query-parameters": "查询参数",
|
"label.query-parameters": "查询参数",
|
||||||
"label.realtime": "实时",
|
"label.realtime": "实时",
|
||||||
"label.referrer": "Referrer",
|
"label.referrer": "来源",
|
||||||
"label.referrers": "来源域名",
|
"label.referrers": "来源域名",
|
||||||
"label.refresh": "刷新",
|
"label.refresh": "刷新",
|
||||||
"label.regenerate": "重新生成",
|
"label.regenerate": "重新生成",
|
||||||
"label.region": "Region",
|
"label.region": "州/省",
|
||||||
"label.regions": "州/省",
|
"label.regions": "州/省",
|
||||||
"label.remove": "移除",
|
"label.remove": "移除",
|
||||||
"label.reports": "报告",
|
"label.reports": "报告",
|
||||||
"label.required": "必填",
|
"label.required": "必填",
|
||||||
"label.reset": "重置",
|
"label.reset": "重置",
|
||||||
"label.reset-website": "重置统计数据",
|
"label.reset-website": "重置统计数据",
|
||||||
"label.retention": "Retention",
|
"label.retention": "保留",
|
||||||
"label.role": "角色",
|
"label.role": "角色",
|
||||||
"label.run-query": "查询",
|
"label.run-query": "查询",
|
||||||
"label.save": "保存",
|
"label.save": "保存",
|
||||||
@ -138,9 +138,9 @@
|
|||||||
"label.team-guest": "团队访客",
|
"label.team-guest": "团队访客",
|
||||||
"label.team-id": "团队 ID",
|
"label.team-id": "团队 ID",
|
||||||
"label.team-member": "团队成员",
|
"label.team-member": "团队成员",
|
||||||
"label.team-name": "Team name",
|
"label.team-name": "团队名称",
|
||||||
"label.team-owner": "团队所有者",
|
"label.team-owner": "团队所有者",
|
||||||
"label.team-websites": "Team websites",
|
"label.team-websites": "团队网站",
|
||||||
"label.teams": "团队",
|
"label.teams": "团队",
|
||||||
"label.theme": "主题",
|
"label.theme": "主题",
|
||||||
"label.this-month": "本月",
|
"label.this-month": "本月",
|
||||||
@ -155,19 +155,19 @@
|
|||||||
"label.tracking-code": "跟踪代码",
|
"label.tracking-code": "跟踪代码",
|
||||||
"label.true": "是",
|
"label.true": "是",
|
||||||
"label.type": "类型",
|
"label.type": "类型",
|
||||||
"label.unique": "Unique",
|
"label.unique": "独立",
|
||||||
"label.unique-visitors": "独立访客",
|
"label.unique-visitors": "独立访客",
|
||||||
"label.unknown": "未知",
|
"label.unknown": "未知",
|
||||||
"label.untitled": "未命名",
|
"label.untitled": "未命名",
|
||||||
"label.url": "URL",
|
"label.url": "网址",
|
||||||
"label.urls": "URLs",
|
"label.urls": "网址",
|
||||||
"label.user": "用户",
|
"label.user": "用户",
|
||||||
"label.username": "用户名",
|
"label.username": "用户名",
|
||||||
"label.users": "用户",
|
"label.users": "用户",
|
||||||
"label.value": "值",
|
"label.value": "值",
|
||||||
"label.view": "查看",
|
"label.view": "查看",
|
||||||
"label.view-details": "查看更多",
|
"label.view-details": "查看更多",
|
||||||
"label.view-only": "View only",
|
"label.view-only": "仅浏览量",
|
||||||
"label.views": "浏览量",
|
"label.views": "浏览量",
|
||||||
"label.visitors": "访客",
|
"label.visitors": "访客",
|
||||||
"label.website": "网站",
|
"label.website": "网站",
|
||||||
@ -183,7 +183,7 @@
|
|||||||
"message.delete-website": "确定删除该网站, 请在下面的输入框中输入 {confirmation} 进行二次确认。",
|
"message.delete-website": "确定删除该网站, 请在下面的输入框中输入 {confirmation} 进行二次确认。",
|
||||||
"message.delete-website-warning": "所有相关数据将会被删除。",
|
"message.delete-website-warning": "所有相关数据将会被删除。",
|
||||||
"message.error": "出现错误。",
|
"message.error": "出现错误。",
|
||||||
"message.event-log": "{event} on {url}",
|
"message.event-log": "{url}上的{event}",
|
||||||
"message.go-to-settings": "去设置",
|
"message.go-to-settings": "去设置",
|
||||||
"message.incorrect-username-password": "用户名或密码不正确。",
|
"message.incorrect-username-password": "用户名或密码不正确。",
|
||||||
"message.invalid-domain": "无效域名",
|
"message.invalid-domain": "无效域名",
|
||||||
|
@ -57,6 +57,14 @@ export function getDevice(screen, os) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getRegionCode(country, region) {
|
||||||
|
if (!country || !region) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return region.includes('-') ? region : `${country}-${region}`;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getLocation(ip, req) {
|
export async function getLocation(ip, req) {
|
||||||
// Ignore local ips
|
// Ignore local ips
|
||||||
if (await isLocalhost(ip)) {
|
if (await isLocalhost(ip)) {
|
||||||
@ -71,7 +79,7 @@ export async function getLocation(ip, req) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
country,
|
country,
|
||||||
subdivision1: subdivision1.includes('-') ? subdivision1 : `${country}-${subdivision1}`,
|
subdivision1: getRegionCode(country, subdivision1),
|
||||||
city,
|
city,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -84,7 +92,7 @@ export async function getLocation(ip, req) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
country,
|
country,
|
||||||
subdivision1: subdivision1.includes('-') ? subdivision1 : `${country}-${subdivision1}`,
|
subdivision1: getRegionCode(country, subdivision1),
|
||||||
city,
|
city,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -122,11 +130,3 @@ export async function getClientInfo(req: NextApiRequestCollect, { screen }) {
|
|||||||
|
|
||||||
return { userAgent, browser, os, ip, country, subdivision1, subdivision2, city, device };
|
return { userAgent, browser, os, ip, country, subdivision1, subdivision2, city, device };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getJsonBody<T>(req): T {
|
|
||||||
if ((req.headers['content-type'] || '').indexOf('text/plain') !== -1) {
|
|
||||||
return JSON.parse(req.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
return req.body;
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { isUuid, secret, uuid } from 'lib/crypto';
|
import { isUuid, secret, uuid } from 'lib/crypto';
|
||||||
import { getClientInfo, getJsonBody } from 'lib/detect';
|
import { getClientInfo } from 'lib/detect';
|
||||||
import { parseToken } from 'next-basics';
|
import { parseToken } from 'next-basics';
|
||||||
import { CollectRequestBody, NextApiRequestCollect } from 'pages/api/send';
|
import { NextApiRequestCollect } from 'pages/api/send';
|
||||||
import { createSession } from 'queries';
|
import { createSession } from 'queries';
|
||||||
import cache from './cache';
|
import cache from './cache';
|
||||||
import clickhouse from './clickhouse';
|
import clickhouse from './clickhouse';
|
||||||
@ -22,7 +22,7 @@ export async function findSession(req: NextApiRequestCollect): Promise<{
|
|||||||
city: any;
|
city: any;
|
||||||
ownerId: string;
|
ownerId: string;
|
||||||
}> {
|
}> {
|
||||||
const { payload } = getJsonBody<CollectRequestBody>(req);
|
const { payload } = req.body;
|
||||||
|
|
||||||
if (!payload) {
|
if (!payload) {
|
||||||
throw new Error('Invalid payload.');
|
throw new Error('Invalid payload.');
|
||||||
|
@ -23,7 +23,6 @@ export interface UserPasswordRequestBody {
|
|||||||
|
|
||||||
const schema = {
|
const schema = {
|
||||||
POST: yup.object().shape({
|
POST: yup.object().shape({
|
||||||
id: yup.string().uuid().required(),
|
|
||||||
currentPassword: yup.string().required(),
|
currentPassword: yup.string().required(),
|
||||||
newPassword: yup.string().min(8).required(),
|
newPassword: yup.string().min(8).required(),
|
||||||
}),
|
}),
|
||||||
|
@ -3,11 +3,11 @@ import ipaddr from 'ipaddr.js';
|
|||||||
import isbot from 'isbot';
|
import isbot from 'isbot';
|
||||||
import { COLLECTION_TYPE, HOSTNAME_REGEX } from 'lib/constants';
|
import { COLLECTION_TYPE, HOSTNAME_REGEX } from 'lib/constants';
|
||||||
import { secret } from 'lib/crypto';
|
import { secret } from 'lib/crypto';
|
||||||
import { getIpAddress, getJsonBody } from 'lib/detect';
|
import { getIpAddress } from 'lib/detect';
|
||||||
import { useCors, useSession, useValidate } from 'lib/middleware';
|
import { useCors, useSession, useValidate } from 'lib/middleware';
|
||||||
import { CollectionType, YupRequest } from 'lib/types';
|
import { CollectionType, YupRequest } from 'lib/types';
|
||||||
import { NextApiRequest, NextApiResponse } from 'next';
|
import { NextApiRequest, NextApiResponse } from 'next';
|
||||||
import { badRequest, createToken, forbidden, ok, send } from 'next-basics';
|
import { badRequest, createToken, forbidden, methodNotAllowed, ok, send } from 'next-basics';
|
||||||
import { saveEvent, saveSessionData } from 'queries';
|
import { saveEvent, saveSessionData } from 'queries';
|
||||||
import * as yup from 'yup';
|
import * as yup from 'yup';
|
||||||
|
|
||||||
@ -73,11 +73,12 @@ const schema = {
|
|||||||
export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
|
export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
|
||||||
await useCors(req, res);
|
await useCors(req, res);
|
||||||
|
|
||||||
|
if (req.method === 'POST') {
|
||||||
if (isbot(req.headers['user-agent']) && !process.env.DISABLE_BOT_CHECK) {
|
if (isbot(req.headers['user-agent']) && !process.env.DISABLE_BOT_CHECK) {
|
||||||
return ok(res);
|
return ok(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { type, payload } = getJsonBody<CollectRequestBody>(req);
|
const { type, payload } = req.body;
|
||||||
|
|
||||||
req.yup = schema;
|
req.yup = schema;
|
||||||
await useValidate(req, res);
|
await useValidate(req, res);
|
||||||
@ -138,6 +139,9 @@ export default async (req: NextApiRequestCollect, res: NextApiResponse) => {
|
|||||||
const token = createToken(session, secret());
|
const token = createToken(session, secret());
|
||||||
|
|
||||||
return send(res, token);
|
return send(res, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
return methodNotAllowed(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
async function hasBlockedIp(req: NextApiRequestCollect) {
|
async function hasBlockedIp(req: NextApiRequestCollect) {
|
||||||
|
@ -42,8 +42,13 @@ export default async (
|
|||||||
} = req.auth;
|
} = req.auth;
|
||||||
|
|
||||||
if (req.method === 'GET') {
|
if (req.method === 'GET') {
|
||||||
|
if (!req.query.id) {
|
||||||
req.query.id = userId;
|
req.query.id = userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!req.query.pageSize) {
|
||||||
req.query.pageSize = 100;
|
req.query.pageSize = 100;
|
||||||
|
}
|
||||||
|
|
||||||
return userWebsites(req as any, res);
|
return userWebsites(req as any, res);
|
||||||
}
|
}
|
||||||
|
@ -142,6 +142,7 @@ export async function getReports(
|
|||||||
...pageFilters,
|
...pageFilters,
|
||||||
...(options?.include && { include: options.include }),
|
...(options?.include && { include: options.include }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const count = await prisma.client.report.count({
|
const count = await prisma.client.report.count({
|
||||||
where,
|
where,
|
||||||
});
|
});
|
||||||
|
@ -135,6 +135,7 @@ export async function getTeams(
|
|||||||
...pageFilters,
|
...pageFilters,
|
||||||
...(options?.include && { include: options?.include }),
|
...(options?.include && { include: options?.include }),
|
||||||
});
|
});
|
||||||
|
|
||||||
const count = await prisma.client.team.count({ where });
|
const count = await prisma.client.team.count({ where });
|
||||||
|
|
||||||
return { data: teams, count, ...getParameters };
|
return { data: teams, count, ...getParameters };
|
||||||
|
@ -107,7 +107,8 @@ export async function getWebsites(
|
|||||||
...pageFilters,
|
...pageFilters,
|
||||||
...(options?.include && { include: options.include }),
|
...(options?.include && { include: options.include }),
|
||||||
});
|
});
|
||||||
const count = await prisma.client.website.count({ where });
|
|
||||||
|
const count = await prisma.client.website.count({ where: { ...where, deletedAt: null } });
|
||||||
|
|
||||||
return { data: websites, count, ...getParameters };
|
return { data: websites, count, ...getParameters };
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user