Compare commits

...

7 commits

Author SHA1 Message Date
Mike Cao
33cb195fd0 Merge remote-tracking branch 'origin/dev' into dev
Some checks are pending
Node.js CI / build (postgresql, 18.18, 10) (push) Waiting to run
# Conflicts:
#	package.json
#	pnpm-lock.yaml
#	src/app/(main)/links/[linkId]/LinkHeader.tsx
#	src/app/(main)/pixels/[pixelId]/PixelHeader.tsx
2025-12-03 15:13:50 -08:00
Mike Cao
64767b1896 Updated next. Fixed link RSC fetch. 2025-12-03 15:11:40 -08:00
Francis Cao
be1b787789 Merge branch 'dependabot/npm_and_yarn/next-15.5.7' of https://github.com/umami-software/umami into dev 2025-12-03 15:00:47 -08:00
Francis Cao
dae7327ed3 Fix date range increment function
Closes #3828
2025-12-03 14:47:56 -08:00
dependabot[bot]
a06490af74
Bump next from 15.5.3 to 15.5.7
Bumps [next](https://github.com/vercel/next.js) from 15.5.3 to 15.5.7.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.5.3...v15.5.7)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 15.5.7
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-03 19:53:10 +00:00
Francis Cao
65f657dd23 Revert "prisma schema boards + varchar length increase"
Some checks are pending
Create docker images (cloud) / Build, push, and deploy (push) Waiting to run
Node.js CI / build (postgresql, 18.18, 10) (push) Waiting to run
This reverts commit cb034a1371.
2025-12-03 11:08:54 -08:00
Francis Cao
6b584338e3 fix PageHeader type errors 2025-12-03 11:06:03 -08:00
12 changed files with 1174 additions and 1244 deletions

View file

@ -1,5 +1,7 @@
ARG NODE_IMAGE_VERSION="22-alpine"
# Install dependencies only when needed # Install dependencies only when needed
FROM node:22-alpine AS deps FROM node:${NODE_IMAGE_VERSION} 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
@ -8,7 +10,7 @@ RUN npm install -g pnpm
RUN pnpm install --frozen-lockfile RUN pnpm install --frozen-lockfile
# Rebuild the source code only when needed # Rebuild the source code only when needed
FROM node:22-alpine AS builder FROM node:${NODE_IMAGE_VERSION} AS builder
WORKDIR /app WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules COPY --from=deps /app/node_modules ./node_modules
COPY . . COPY . .
@ -25,9 +27,10 @@ ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build-docker RUN npm run build-docker
# Production image, copy all the files and run next # Production image, copy all the files and run next
FROM node:22-alpine AS runner FROM node:${NODE_IMAGE_VERSION} AS runner
WORKDIR /app WORKDIR /app
ARG PRISMA_VERSION="6.19.0"
ARG NODE_OPTIONS ARG NODE_OPTIONS
ENV NODE_ENV=production ENV NODE_ENV=production
@ -36,13 +39,14 @@ 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 npm install -g pnpm
RUN set -x \ RUN set -x \
&& apk add --no-cache curl && apk add --no-cache curl \
&& npm install -g pnpm
# Script dependencies # Script dependencies
RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver prisma@6.18.0 @prisma/adapter-pg@6.18.0 RUN pnpm --allow-build='@prisma/engines' add npm-run-all dotenv chalk semver \
prisma@${PRISMA_VERSION} \
@prisma/adapter-pg@${PRISMA_VERSION}
COPY --from=builder --chown=nextjs:nodejs /app/public ./public COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/prisma ./prisma COPY --from=builder /app/prisma ./prisma

View file

@ -72,7 +72,7 @@
"@prisma/extension-read-replicas": "^0.4.1", "@prisma/extension-read-replicas": "^0.4.1",
"@react-spring/web": "^10.0.3", "@react-spring/web": "^10.0.3",
"@svgr/cli": "^8.1.0", "@svgr/cli": "^8.1.0",
"@tanstack/react-query": "^5.90.5", "@tanstack/react-query": "^5.90.11",
"@umami/react-zen": "^0.211.0", "@umami/react-zen": "^0.211.0",
"@umami/redis-client": "^0.29.0", "@umami/redis-client": "^0.29.0",
"bcryptjs": "^3.0.2", "bcryptjs": "^3.0.2",
@ -92,7 +92,7 @@
"esbuild": "^0.25.11", "esbuild": "^0.25.11",
"fs-extra": "^11.3.2", "fs-extra": "^11.3.2",
"immer": "^10.2.0", "immer": "^10.2.0",
"ipaddr.js": "^2.0.1", "ipaddr.js": "^2.3.0",
"is-ci": "^3.0.1", "is-ci": "^3.0.1",
"is-docker": "^3.0.0", "is-docker": "^3.0.0",
"is-localhost-ip": "^2.0.0", "is-localhost-ip": "^2.0.0",
@ -102,15 +102,15 @@
"kafkajs": "^2.1.0", "kafkajs": "^2.1.0",
"lucide-react": "^0.543.0", "lucide-react": "^0.543.0",
"maxmind": "^5.0.0", "maxmind": "^5.0.0",
"next": "15.5.3", "next": "^15.5.7",
"node-fetch": "^3.2.8", "node-fetch": "^3.2.8",
"npm-run-all": "^4.1.5", "npm-run-all": "^4.1.5",
"papaparse": "^5.5.3", "papaparse": "^5.5.3",
"pg": "^8.16.3", "pg": "^8.16.3",
"prisma": "^6.18.0", "prisma": "^6.18.0",
"pure-rand": "^7.0.1", "pure-rand": "^7.0.1",
"react": "^19.2.0", "react": "^19.2.1",
"react-dom": "^19.2.0", "react-dom": "^19.2.1",
"react-error-boundary": "^4.0.4", "react-error-boundary": "^4.0.4",
"react-intl": "^7.1.14", "react-intl": "^7.1.14",
"react-simple-maps": "^2.3.0", "react-simple-maps": "^2.3.0",
@ -122,13 +122,13 @@
"thenby": "^1.3.4", "thenby": "^1.3.4",
"ua-parser-js": "^2.0.6", "ua-parser-js": "^2.0.6",
"uuid": "^11.1.0", "uuid": "^11.1.0",
"zod": "^4.1.12", "zod": "^4.1.13",
"zustand": "^5.0.8" "zustand": "^5.0.9"
}, },
"devDependencies": { "devDependencies": {
"@biomejs/biome": "^2.3.6", "@biomejs/biome": "^2.3.8",
"@formatjs/cli": "^4.2.29", "@formatjs/cli": "^4.2.29",
"@netlify/plugin-nextjs": "^5.14.4", "@netlify/plugin-nextjs": "^5.15.1",
"@rollup/plugin-alias": "^5.0.0", "@rollup/plugin-alias": "^5.0.0",
"@rollup/plugin-commonjs": "^25.0.4", "@rollup/plugin-commonjs": "^25.0.4",
"@rollup/plugin-json": "^6.0.0", "@rollup/plugin-json": "^6.0.0",
@ -138,7 +138,7 @@
"@rollup/plugin-typescript": "^12.3.0", "@rollup/plugin-typescript": "^12.3.0",
"@types/jest": "^30.0.0", "@types/jest": "^30.0.0",
"@types/node": "^24.9.2", "@types/node": "^24.9.2",
"@types/react": "^19.2.2", "@types/react": "^19.2.7",
"@types/react-dom": "^19.2.2", "@types/react-dom": "^19.2.2",
"@types/react-window": "^1.8.8", "@types/react-window": "^1.8.8",
"babel-plugin-react-compiler": "19.1.0-rc.2", "babel-plugin-react-compiler": "19.1.0-rc.2",
@ -156,7 +156,7 @@
"rollup": "^4.52.5", "rollup": "^4.52.5",
"rollup-plugin-copy": "^3.4.0", "rollup-plugin-copy": "^3.4.0",
"rollup-plugin-delete": "^3.0.1", "rollup-plugin-delete": "^3.0.1",
"rollup-plugin-dts": "^6.2.3", "rollup-plugin-dts": "^6.3.0",
"rollup-plugin-node-externals": "^8.1.1", "rollup-plugin-node-externals": "^8.1.1",
"rollup-plugin-peer-deps-external": "^2.2.4", "rollup-plugin-peer-deps-external": "^2.2.4",
"rollup-plugin-postcss": "^4.0.2", "rollup-plugin-postcss": "^4.0.2",
@ -165,7 +165,7 @@
"stylelint-config-prettier": "^9.0.3", "stylelint-config-prettier": "^9.0.3",
"stylelint-config-recommended": "^14.0.0", "stylelint-config-recommended": "^14.0.0",
"tar": "^6.1.2", "tar": "^6.1.2",
"ts-jest": "^29.4.5", "ts-jest": "^29.4.6",
"ts-node": "^10.9.1", "ts-node": "^10.9.1",
"tsup": "^8.5.0", "tsup": "^8.5.0",
"tsx": "^4.19.0", "tsx": "^4.19.0",

2220
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff

View file

@ -1,33 +0,0 @@
-- CreateTable
CREATE TABLE "board" (
"board_id" UUID NOT NULL,
"type" VARCHAR(50) NOT NULL,
"name" VARCHAR(200) NOT NULL,
"description" VARCHAR(500) NOT NULL,
"parameters" JSONB NOT NULL,
"slug" VARCHAR(100) NOT NULL,
"user_id" UUID,
"team_id" UUID,
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMPTZ(6),
CONSTRAINT "board_pkey" PRIMARY KEY ("board_id")
);
-- CreateIndex
CREATE UNIQUE INDEX "board_board_id_key" ON "board"("board_id");
-- CreateIndex
CREATE UNIQUE INDEX "board_slug_key" ON "board"("slug");
-- CreateIndex
CREATE INDEX "board_slug_idx" ON "board"("slug");
-- CreateIndex
CREATE INDEX "board_user_id_idx" ON "board"("user_id");
-- CreateIndex
CREATE INDEX "board_team_id_idx" ON "board"("team_id");
-- CreateIndex
CREATE INDEX "board_created_at_idx" ON "board"("created_at");

View file

@ -1,16 +0,0 @@
-- AlterTable
ALTER TABLE "website_event" ALTER COLUMN "url_path" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "url_query" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "referrer_path" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "referrer_query" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "fbclid" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "gclid" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "li_fat_id" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "msclkid" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "ttclid" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "twclid" SET DATA TYPE VARCHAR(1024),
ALTER COLUMN "utm_campaign" SET DATA TYPE VARCHAR(512),
ALTER COLUMN "utm_content" SET DATA TYPE VARCHAR(512),
ALTER COLUMN "utm_medium" SET DATA TYPE VARCHAR(512),
ALTER COLUMN "utm_source" SET DATA TYPE VARCHAR(512),
ALTER COLUMN "utm_term" SET DATA TYPE VARCHAR(512);

View file

@ -27,7 +27,6 @@ model User {
pixels Pixel[] @relation("user") pixels Pixel[] @relation("user")
teams TeamUser[] teams TeamUser[]
reports Report[] reports Report[]
boards Board[] @relation("user")
@@map("user") @@map("user")
} }
@ -100,23 +99,23 @@ model WebsiteEvent {
sessionId String @map("session_id") @db.Uuid sessionId String @map("session_id") @db.Uuid
visitId String @map("visit_id") @db.Uuid visitId String @map("visit_id") @db.Uuid
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6) createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
urlPath String @map("url_path") @db.VarChar(1024) urlPath String @map("url_path") @db.VarChar(500)
urlQuery String? @map("url_query") @db.VarChar(1024) urlQuery String? @map("url_query") @db.VarChar(500)
utmSource String? @map("utm_source") @db.VarChar(512) utmSource String? @map("utm_source") @db.VarChar(255)
utmMedium String? @map("utm_medium") @db.VarChar(512) utmMedium String? @map("utm_medium") @db.VarChar(255)
utmCampaign String? @map("utm_campaign") @db.VarChar(512) utmCampaign String? @map("utm_campaign") @db.VarChar(255)
utmContent String? @map("utm_content") @db.VarChar(512) utmContent String? @map("utm_content") @db.VarChar(255)
utmTerm String? @map("utm_term") @db.VarChar(512) utmTerm String? @map("utm_term") @db.VarChar(255)
referrerPath String? @map("referrer_path") @db.VarChar(1024) referrerPath String? @map("referrer_path") @db.VarChar(500)
referrerQuery String? @map("referrer_query") @db.VarChar(1024) referrerQuery String? @map("referrer_query") @db.VarChar(500)
referrerDomain String? @map("referrer_domain") @db.VarChar(500) referrerDomain String? @map("referrer_domain") @db.VarChar(500)
pageTitle String? @map("page_title") @db.VarChar(500) pageTitle String? @map("page_title") @db.VarChar(500)
gclid String? @db.VarChar(1024) gclid String? @db.VarChar(255)
fbclid String? @db.VarChar(1024) fbclid String? @db.VarChar(255)
msclkid String? @db.VarChar(1024) msclkid String? @db.VarChar(255)
ttclid String? @db.VarChar(1024) ttclid String? @db.VarChar(255)
lifatid String? @map("li_fat_id") @db.VarChar(1024) lifatid String? @map("li_fat_id") @db.VarChar(255)
twclid String? @db.VarChar(1024) twclid String? @db.VarChar(255)
eventType Int @default(1) @map("event_type") @db.Integer eventType Int @default(1) @map("event_type") @db.Integer
eventName String? @map("event_name") @db.VarChar(50) eventName String? @map("event_name") @db.VarChar(50)
tag String? @db.VarChar(50) tag String? @db.VarChar(50)
@ -200,7 +199,6 @@ model Team {
members TeamUser[] members TeamUser[]
links Link[] links Link[]
pixels Pixel[] pixels Pixel[]
boards Board[]
@@index([accessCode]) @@index([accessCode])
@@map("team") @@map("team")
@ -318,25 +316,3 @@ model Pixel {
@@index([createdAt]) @@index([createdAt])
@@map("pixel") @@map("pixel")
} }
model Board {
id String @id() @unique() @map("board_id") @db.Uuid
type String @db.VarChar(50)
name String @db.VarChar(200)
description String @db.VarChar(500)
parameters Json
slug String @unique() @db.VarChar(100)
userId String? @map("user_id") @db.Uuid
teamId String? @map("team_id") @db.Uuid
createdAt DateTime? @default(now()) @map("created_at") @db.Timestamptz(6)
updatedAt DateTime? @updatedAt @map("updated_at") @db.Timestamptz(6)
user User? @relation("user", fields: [userId], references: [id])
team Team? @relation(fields: [teamId], references: [id])
@@index([slug])
@@index([userId])
@@index([teamId])
@@index([createdAt])
@@map("board")
}

View file

@ -1,4 +1,4 @@
import { Icon, Text } from '@umami/react-zen'; import { IconLabel } from '@umami/react-zen';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
import { PageHeader } from '@/components/common/PageHeader'; import { PageHeader } from '@/components/common/PageHeader';
import { useLink, useMessages, useSlug } from '@/components/hooks'; import { useLink, useMessages, useSlug } from '@/components/hooks';
@ -10,12 +10,9 @@ export function LinkHeader() {
const link = useLink(); const link = useLink();
return ( return (
<PageHeader title={link.name} description={link.url} icon={<Link />} marginBottom="3"> <PageHeader title={link.name} description={link.url} icon={<Link />}>
<LinkButton href={getSlugUrl(link.slug)} target="_blank" prefetch={false}> <LinkButton href={getSlugUrl(link.slug)} target="_blank" prefetch={false} asAnchor>
<Icon> <IconLabel icon={<ExternalLink />} label={formatMessage(labels.view)} />
<ExternalLink />
</Icon>
<Text>{formatMessage(labels.view)}</Text>
</LinkButton> </LinkButton>
</PageHeader> </PageHeader>
); );

View file

@ -1,4 +1,4 @@
import { Icon, Text } from '@umami/react-zen'; import { IconLabel } from '@umami/react-zen';
import { LinkButton } from '@/components/common/LinkButton'; import { LinkButton } from '@/components/common/LinkButton';
import { PageHeader } from '@/components/common/PageHeader'; import { PageHeader } from '@/components/common/PageHeader';
import { useMessages, usePixel, useSlug } from '@/components/hooks'; import { useMessages, usePixel, useSlug } from '@/components/hooks';
@ -10,12 +10,9 @@ export function PixelHeader() {
const pixel = usePixel(); const pixel = usePixel();
return ( return (
<PageHeader title={pixel.name} icon={<Grid2x2 />} marginBottom="3"> <PageHeader title={pixel.name} icon={<Grid2x2 />}>
<LinkButton href={getSlugUrl(pixel.slug)} target="_blank" prefetch={false}> <LinkButton href={getSlugUrl(pixel.slug)} target="_blank" prefetch={false} asAnchor>
<Icon> <IconLabel icon={<ExternalLink />} label={formatMessage(labels.view)} />
<ExternalLink />
</Icon>
<Text>{formatMessage(labels.view)}</Text>
</LinkButton> </LinkButton>
</PageHeader> </PageHeader>
); );

View file

@ -23,7 +23,6 @@ export function WebsiteHeader({ showActions }: { showActions?: boolean }) {
<PageHeader <PageHeader
title={website.name} title={website.name}
icon={<Favicon domain={website.domain} />} icon={<Favicon domain={website.domain} />}
marginBottom="3"
titleHref={renderUrl(`/websites/${website.id}`, false)} titleHref={renderUrl(`/websites/${website.id}`, false)}
> >
<Row alignItems="center" gap="6" wrap="wrap"> <Row alignItems="center" gap="6" wrap="wrap">

View file

@ -9,6 +9,7 @@ export interface LinkButtonProps extends ButtonProps {
scroll?: boolean; scroll?: boolean;
variant?: any; variant?: any;
prefetch?: boolean; prefetch?: boolean;
asAnchor?: boolean;
children?: ReactNode; children?: ReactNode;
} }
@ -19,15 +20,22 @@ export function LinkButton({
target, target,
prefetch, prefetch,
children, children,
asAnchor,
...props ...props
}: LinkButtonProps) { }: LinkButtonProps) {
const { dir } = useLocale(); const { dir } = useLocale();
return ( return (
<Button {...props} variant={variant} asChild> <Button {...props} variant={variant} asChild>
<Link href={href} dir={dir} scroll={scroll} target={target} prefetch={prefetch}> {asAnchor ? (
{children} <a href={href} target={target}>
</Link> {children}
</a>
) : (
<Link href={href} dir={dir} scroll={scroll} target={target} prefetch={prefetch}>
{children}
</Link>
)}
</Button> </Button>
); );
} }

View file

@ -50,7 +50,9 @@ export function PageHeader({
</Text> </Text>
)} )}
</Column> </Column>
<Row justifyContent="flex-end">{children}</Row> <Row justifyContent="flex-end" alignItems="center">
{children}
</Row>
</Grid> </Grid>
); );
} }

View file

@ -1,6 +1,6 @@
import { Button, Icon, ListItem, Row, Select, Text } from '@umami/react-zen'; import { Button, Icon, ListItem, Row, Select, Text } from '@umami/react-zen';
import { isAfter } from 'date-fns'; import { isAfter } from 'date-fns';
import { useCallback, useMemo } from 'react'; import { useMemo } from 'react';
import { useDateRange, useDateRangeQuery, useMessages, useNavigation } from '@/components/hooks'; import { useDateRange, useDateRangeQuery, useMessages, useNavigation } from '@/components/hooks';
import { ChevronRight } from '@/components/icons'; import { ChevronRight } from '@/components/icons';
import { getDateRangeValue } from '@/lib/date'; import { getDateRangeValue } from '@/lib/date';
@ -45,13 +45,9 @@ export function WebsiteDateFilter({
} }
}; };
const handleIncrement = useCallback( const handleIncrement = increment => {
(increment: number) => { router.push(updateParams({ offset: Number(offset) + increment }));
router.push(updateParams({ offset: +offset + increment })); };
},
[offset],
);
const handleSelect = (compare: any) => { const handleSelect = (compare: any) => {
router.push(updateParams({ compare })); router.push(updateParams({ compare }));
}; };