mirror of
https://github.com/kremalicious/umami.git
synced 2024-11-16 02:05:04 +01:00
commit
4f8bcb81d9
67
Dockerfile
67
Dockerfile
@ -1,45 +1,52 @@
|
|||||||
# Build image
|
# Install dependencies only when needed
|
||||||
FROM node:12.22-alpine AS build
|
FROM node:16-alpine AS deps
|
||||||
ARG BASE_PATH
|
# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed.
|
||||||
ARG DATABASE_TYPE
|
RUN apk add --no-cache libc6-compat
|
||||||
|
WORKDIR /app
|
||||||
|
COPY package.json yarn.lock ./
|
||||||
|
RUN yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
# Rebuild the source code only when needed
|
||||||
|
FROM node:16-alpine AS builder
|
||||||
ENV BASE_PATH=$BASE_PATH
|
ENV BASE_PATH=$BASE_PATH
|
||||||
ENV DATABASE_URL "postgresql://umami:umami@db:5432/umami"
|
ENV DATABASE_URL "postgresql://umami:umami@db:5432/umami"
|
||||||
ENV DATABASE_TYPE=$DATABASE_TYPE
|
ENV DATABASE_TYPE=$DATABASE_TYPE
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY . .
|
||||||
|
|
||||||
WORKDIR /build
|
# Next.js collects completely anonymous telemetry data about general usage.
|
||||||
|
# Learn more here: https://nextjs.org/telemetry
|
||||||
|
# Uncomment the following line in case you want to disable telemetry during the build.
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED 1
|
||||||
|
|
||||||
RUN yarn config set --home enableTelemetry 0
|
|
||||||
COPY package.json yarn.lock /build/
|
|
||||||
|
|
||||||
# Install only the production dependencies
|
|
||||||
RUN yarn install --production --frozen-lockfile
|
|
||||||
|
|
||||||
# Cache these modules for production
|
|
||||||
RUN cp -R node_modules/ prod_node_modules/
|
|
||||||
|
|
||||||
# Install development dependencies
|
|
||||||
RUN yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
COPY . /build
|
|
||||||
RUN yarn next telemetry disable
|
|
||||||
RUN yarn build
|
RUN yarn build
|
||||||
|
|
||||||
# Production image
|
# Production image, copy all the files and run next
|
||||||
FROM node:12.22-alpine AS production
|
FROM node:16-alpine AS runner
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy cached dependencies
|
ENV NODE_ENV production
|
||||||
COPY --from=build /build/prod_node_modules ./node_modules
|
# Uncomment the following line in case you want to disable telemetry during runtime.
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED 1
|
||||||
|
|
||||||
# Copy generated Prisma client
|
RUN addgroup --system --gid 1001 nodejs
|
||||||
COPY --from=build /build/node_modules/.prisma/ ./node_modules/.prisma/
|
RUN adduser --system --uid 1001 nextjs
|
||||||
|
|
||||||
COPY --from=build /build/yarn.lock /build/package.json ./
|
# You only need to copy next.config.js if you are NOT using the default configuration
|
||||||
COPY --from=build /build/.next ./.next
|
COPY --from=builder /app/next.config.js ./
|
||||||
COPY --from=build /build/public ./public
|
COPY --from=builder /app/public ./public
|
||||||
|
COPY --from=builder /app/package.json ./package.json
|
||||||
|
|
||||||
USER node
|
# Automatically leverage output traces to reduce image size
|
||||||
|
# https://nextjs.org/docs/advanced-features/output-file-tracing
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
|
||||||
|
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
|
||||||
|
|
||||||
|
USER nextjs
|
||||||
|
|
||||||
EXPOSE 3000
|
EXPOSE 3000
|
||||||
CMD ["yarn", "start"]
|
|
||||||
|
ENV PORT 3000
|
||||||
|
|
||||||
|
CMD ["node", "server.js"]
|
||||||
|
16
README.md
16
README.md
@ -19,12 +19,18 @@ See [Running on Railway](https://umami.is/docs/running-on-railway) to get starte
|
|||||||
- A server with Node.js 12 or newer
|
- A server with Node.js 12 or newer
|
||||||
- A database (MySQL or Postgresql)
|
- A database (MySQL or Postgresql)
|
||||||
|
|
||||||
|
### Install Yarn (if needed)
|
||||||
|
|
||||||
|
```
|
||||||
|
npm install -g yarn
|
||||||
|
```
|
||||||
|
|
||||||
### Get the source code and install packages
|
### Get the source code and install packages
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone https://github.com/mikecao/umami.git
|
git clone https://github.com/mikecao/umami.git
|
||||||
cd umami
|
cd umami
|
||||||
npm install
|
yarn install
|
||||||
```
|
```
|
||||||
|
|
||||||
### Create database tables
|
### Create database tables
|
||||||
@ -67,13 +73,13 @@ The `HASH_SALT` is used to generate unique values for your installation.
|
|||||||
### Build the application
|
### Build the application
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
### Start the application
|
### Start the application
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm start
|
yarn start
|
||||||
```
|
```
|
||||||
|
|
||||||
By default this will launch the application on `http://localhost:3000`. You will need to either
|
By default this will launch the application on `http://localhost:3000`. You will need to either
|
||||||
@ -104,8 +110,8 @@ To get the latest features, simply do a pull, install any new dependencies, and
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
git pull
|
git pull
|
||||||
npm install
|
yarn install
|
||||||
npm run build
|
yarn build
|
||||||
```
|
```
|
||||||
|
|
||||||
To update the Docker image, simply pull the new images and rebuild:
|
To update the Docker image, simply pull the new images and rebuild:
|
||||||
|
@ -32,7 +32,9 @@ export default function Dashboard() {
|
|||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<PageHeader>
|
<PageHeader>
|
||||||
<div>Dashboard</div>
|
<div>
|
||||||
|
<FormattedMessage id="label.dashboard" defaultMessage="Dashboard" />
|
||||||
|
</div>
|
||||||
<DashboardSettingsButton />
|
<DashboardSettingsButton />
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
<WebsiteList websites={data} showCharts={showCharts} limit={max} />
|
<WebsiteList websites={data} showCharts={showCharts} limit={max} />
|
||||||
|
@ -5,14 +5,14 @@ import useApi from './useApi';
|
|||||||
export default function useFetch(url, options = {}, update = []) {
|
export default function useFetch(url, options = {}, update = []) {
|
||||||
const [response, setResponse] = useState();
|
const [response, setResponse] = useState();
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState();
|
||||||
const [loading, setLoadiing] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [count, setCount] = useState(0);
|
const [count, setCount] = useState(0);
|
||||||
const { get } = useApi();
|
const { get } = useApi();
|
||||||
const { params = {}, headers = {}, disabled, delay = 0, interval, onDataLoad } = options;
|
const { params = {}, headers = {}, disabled, delay = 0, interval, onDataLoad } = options;
|
||||||
|
|
||||||
async function loadData(params) {
|
async function loadData(params) {
|
||||||
try {
|
try {
|
||||||
setLoadiing(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
const time = performance.now();
|
const time = performance.now();
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ export default function useFetch(url, options = {}, update = []) {
|
|||||||
console.error(e);
|
console.error(e);
|
||||||
setError(e);
|
setError(e);
|
||||||
} finally {
|
} finally {
|
||||||
setLoadiing(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@
|
|||||||
"label.settings": "Einstellungen",
|
"label.settings": "Einstellungen",
|
||||||
"label.share-url": "Freigabe-URL",
|
"label.share-url": "Freigabe-URL",
|
||||||
"label.single-day": "Ein Tag",
|
"label.single-day": "Ein Tag",
|
||||||
"label.theme": "Theme",
|
"label.theme": "Thema",
|
||||||
"label.this-month": "Diesen Monat",
|
"label.this-month": "Diesen Monat",
|
||||||
"label.this-week": "Diese Woche",
|
"label.this-week": "Diese Woche",
|
||||||
"label.this-year": "Dieses Jahr",
|
"label.this-year": "Dieses Jahr",
|
||||||
@ -92,7 +92,7 @@
|
|||||||
"metrics.countries": "Länder",
|
"metrics.countries": "Länder",
|
||||||
"metrics.device.desktop": "Desktop",
|
"metrics.device.desktop": "Desktop",
|
||||||
"metrics.device.laptop": "Laptop",
|
"metrics.device.laptop": "Laptop",
|
||||||
"metrics.device.mobile": "Mobiltelefon",
|
"metrics.device.mobile": "Handy",
|
||||||
"metrics.device.tablet": "Tablet",
|
"metrics.device.tablet": "Tablet",
|
||||||
"metrics.devices": "Geräte",
|
"metrics.devices": "Geräte",
|
||||||
"metrics.events": "Ereignisse",
|
"metrics.events": "Ereignisse",
|
||||||
|
@ -6,6 +6,9 @@ module.exports = {
|
|||||||
VERSION: pkg.version,
|
VERSION: pkg.version,
|
||||||
},
|
},
|
||||||
basePath: process.env.BASE_PATH,
|
basePath: process.env.BASE_PATH,
|
||||||
|
experimental: {
|
||||||
|
outputStandalone: true,
|
||||||
|
},
|
||||||
eslint: {
|
eslint: {
|
||||||
ignoreDuringBuilds: true,
|
ignoreDuringBuilds: true,
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "umami",
|
"name": "umami",
|
||||||
"version": "1.31.0",
|
"version": "1.32.0",
|
||||||
"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",
|
||||||
@ -54,7 +54,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/inter": "4.5.7",
|
"@fontsource/inter": "4.5.7",
|
||||||
"@prisma/client": "3.12.0",
|
"@prisma/client": "3.14.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"chalk": "^4.1.1",
|
"chalk": "^4.1.1",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
@ -112,10 +112,10 @@
|
|||||||
"postcss": "^8.4.12",
|
"postcss": "^8.4.12",
|
||||||
"postcss-flexbugs-fixes": "^5.0.2",
|
"postcss-flexbugs-fixes": "^5.0.2",
|
||||||
"postcss-import": "^14.0.2",
|
"postcss-import": "^14.0.2",
|
||||||
"postcss-preset-env": "^7.4.2",
|
"postcss-preset-env": "7.4.3",
|
||||||
"postcss-rtlcss": "^3.6.1",
|
"postcss-rtlcss": "^3.6.1",
|
||||||
"prettier": "^2.6.2",
|
"prettier": "^2.6.2",
|
||||||
"prisma": "3.12.0",
|
"prisma": "3.14.0",
|
||||||
"prompts": "2.4.2",
|
"prompts": "2.4.2",
|
||||||
"rollup": "^2.70.1",
|
"rollup": "^2.70.1",
|
||||||
"rollup-plugin-terser": "^7.0.2",
|
"rollup-plugin-terser": "^7.0.2",
|
||||||
|
@ -24,7 +24,6 @@ const Intl = ({ children }) => {
|
|||||||
export default function App({ Component, pageProps }) {
|
export default function App({ Component, pageProps }) {
|
||||||
const { basePath } = useRouter();
|
const { basePath } = useRouter();
|
||||||
const { dir } = useLocale();
|
const { dir } = useLocale();
|
||||||
const version = process.env.VERSION;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Intl>
|
<Intl>
|
||||||
@ -35,12 +34,6 @@ export default function App({ Component, pageProps }) {
|
|||||||
<link rel="icon" type="image/png" sizes="16x16" href={`${basePath}/favicon-16x16.png`} />
|
<link rel="icon" type="image/png" sizes="16x16" href={`${basePath}/favicon-16x16.png`} />
|
||||||
<link rel="manifest" href={`${basePath}/site.webmanifest`} />
|
<link rel="manifest" href={`${basePath}/site.webmanifest`} />
|
||||||
<link rel="mask-icon" href={`${basePath}/safari-pinned-tab.svg`} color="#5bbad5" />
|
<link rel="mask-icon" href={`${basePath}/safari-pinned-tab.svg`} color="#5bbad5" />
|
||||||
<link
|
|
||||||
rel="preload"
|
|
||||||
href={`https://i.umami.is/icon.png?v=${version}`}
|
|
||||||
as="image"
|
|
||||||
type="image/png"
|
|
||||||
/>
|
|
||||||
<meta name="msapplication-TileColor" content="#da532c" />
|
<meta name="msapplication-TileColor" content="#da532c" />
|
||||||
<meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
|
<meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
|
||||||
<meta name="theme-color" content="#2f2f2f" media="(prefers-color-scheme: dark)" />
|
<meta name="theme-color" content="#2f2f2f" media="(prefers-color-scheme: dark)" />
|
||||||
|
@ -17,7 +17,7 @@ function customScriptName(req) {
|
|||||||
|
|
||||||
function disableLogin(req) {
|
function disableLogin(req) {
|
||||||
if (process.env.DISABLE_LOGIN && req.nextUrl.pathname.endsWith('/login')) {
|
if (process.env.DISABLE_LOGIN && req.nextUrl.pathname.endsWith('/login')) {
|
||||||
return new Response('403 Forbidden', { status: 403 });
|
return new Response('Login is disabled', { status: 403 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,7 +334,7 @@
|
|||||||
"label.theme": [
|
"label.theme": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Theme"
|
"value": "Thema"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"label.this-month": [
|
"label.this-month": [
|
||||||
@ -704,7 +704,7 @@
|
|||||||
"metrics.device.mobile": [
|
"metrics.device.mobile": [
|
||||||
{
|
{
|
||||||
"type": 0,
|
"type": 0,
|
||||||
"value": "Mobiltelefon"
|
"value": "Handy"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metrics.device.tablet": [
|
"metrics.device.tablet": [
|
||||||
|
@ -4,7 +4,7 @@ import semver from 'semver';
|
|||||||
import { VERSION_CHECK } from 'lib/constants';
|
import { VERSION_CHECK } from 'lib/constants';
|
||||||
import { getItem } from 'lib/web';
|
import { getItem } from 'lib/web';
|
||||||
|
|
||||||
const REPO_URL = 'https://api.github.com/repos/mikecao/umami/releases/latest';
|
const REPO_URL = 'https://api.umami.is/v1/updates';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
current: process.env.VERSION,
|
current: process.env.VERSION,
|
||||||
@ -20,7 +20,7 @@ export async function checkVersion() {
|
|||||||
const data = await fetch(REPO_URL, {
|
const data = await fetch(REPO_URL, {
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/vnd.github.v3+json',
|
Accept: 'application/json',
|
||||||
},
|
},
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
@ -36,9 +36,7 @@ export async function checkVersion() {
|
|||||||
|
|
||||||
store.setState(
|
store.setState(
|
||||||
produce(state => {
|
produce(state => {
|
||||||
const { tag_name } = data;
|
const { latest } = data;
|
||||||
|
|
||||||
const latest = tag_name.startsWith('v') ? tag_name.slice(1) : tag_name;
|
|
||||||
const lastCheck = getItem(VERSION_CHECK);
|
const lastCheck = getItem(VERSION_CHECK);
|
||||||
const hasUpdate = latest && semver.gt(latest, current) && lastCheck?.version !== latest;
|
const hasUpdate = latest && semver.gt(latest, current) && lastCheck?.version !== latest;
|
||||||
|
|
||||||
|
@ -122,7 +122,11 @@ import { removeTrailingSlash } from '../lib/url';
|
|||||||
payload,
|
payload,
|
||||||
});
|
});
|
||||||
|
|
||||||
navigator.sendBeacon(`${root}/api/collect`, data);
|
fetch(`${root}/api/collect`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: data,
|
||||||
|
keepalive: true,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const addEvents = node => {
|
const addEvents = node => {
|
||||||
|
Loading…
Reference in New Issue
Block a user