Skip to content

Commit

Permalink
Merge branch 'dev' into analytics
Browse files Browse the repository at this point in the history
  • Loading branch information
mikecao committed Dec 1, 2023
2 parents 1770682 + 3bb82ae commit f16d74e
Show file tree
Hide file tree
Showing 27 changed files with 144 additions and 94 deletions.
1 change: 1 addition & 0 deletions .github/workflows/stale-issues.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ jobs:
operations-per-run: 200
ascending: true
repo-token: ${{ secrets.GITHUB_TOKEN }}
exempt-issue-labels: bug,enhancement
4 changes: 3 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ ENV NEXT_TELEMETRY_DISABLED 1
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

RUN yarn add npm-run-all dotenv prisma semver
RUN set -x \
&& apk add --no-cache curl \
&& yarn add npm-run-all dotenv prisma semver

# You only need to copy next.config.js if you are NOT using the default configuration
COPY --from=builder /app/next.config.js .
Expand Down
12 changes: 6 additions & 6 deletions db/mysql/migrations/02_report_schema_session_data/migration.sql
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
-- AlterTable
ALTER TABLE `event_data` RENAME COLUMN `event_data_type` TO `data_type`;
ALTER TABLE `event_data` RENAME COLUMN `event_date_value` TO `date_value`;
ALTER TABLE `event_data` RENAME COLUMN `event_id` TO `event_data_id`;
ALTER TABLE `event_data` RENAME COLUMN `event_numeric_value` TO `number_value`;
ALTER TABLE `event_data` RENAME COLUMN `event_string_value` TO `string_value`;
ALTER TABLE `event_data` CHANGE `event_data_type` `data_type` INTEGER UNSIGNED NOT NULL;
ALTER TABLE `event_data` CHANGE `event_date_value` `date_value` TIMESTAMP(0) NULL;
ALTER TABLE `event_data` CHANGE `event_id` `event_data_id` VARCHAR(36) NOT NULL;
ALTER TABLE `event_data` CHANGE `event_numeric_value` `number_value` DECIMAL(19,4) NULL;
ALTER TABLE `event_data` CHANGE `event_string_value` `string_value` VARCHAR(500) NULL;

-- CreateTable
CREATE TABLE `session_data` (
Expand Down Expand Up @@ -50,4 +50,4 @@ WHERE data_type = 2;

UPDATE event_data
SET string_value = CONCAT(REPLACE(DATE_FORMAT(date_value, '%Y-%m-%d %T'), ' ', 'T'), 'Z')
WHERE data_type = 4;
WHERE data_type = 4;
5 changes: 5 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@ services:
db:
condition: service_healthy
restart: always
healthcheck:
test: ["CMD-SHELL", "curl http://localhost:3000/api/heartbeat"]
interval: 5s
timeout: 5s
retries: 5
db:
image: postgres:15-alpine
environment:
Expand Down
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@
"dependencies": {
"@clickhouse/client": "^0.2.2",
"@fontsource/inter": "^4.5.15",
"@prisma/client": "5.4.2",
"@prisma/client": "5.6.0",
"@prisma/extension-read-replicas": "^0.3.0",
"@react-spring/web": "^9.7.3",
"@tanstack/react-query": "^4.33.0",
"@umami/prisma-client": "^0.5.0",
"@umami/prisma-client": "^0.7.0",
"@umami/redis-client": "^0.18.0",
"chalk": "^4.1.1",
"chart.js": "^4.2.1",
Expand Down Expand Up @@ -97,9 +97,9 @@
"next-basics": "^0.37.0",
"node-fetch": "^3.2.8",
"npm-run-all": "^4.1.5",
"prisma": "5.4.2",
"prisma": "5.6.0",
"react": "^18.2.0",
"react-basics": "^0.107.0",
"react-basics": "^0.109.0",
"react-beautiful-dnd": "^13.1.0",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.4",
Expand Down
24 changes: 20 additions & 4 deletions src/app/(main)/reports/[id]/FieldFilterForm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState } from 'react';
import { useState, useMemo } from 'react';
import { Form, FormRow, Item, Flexbox, Dropdown, Button } from 'react-basics';
import { useMessages, useFilters, useFormat } from 'components/hooks';
import { useMessages, useFilters, useFormat, useLocale } from 'components/hooks';
import styles from './FieldFilterForm.module.css';

export default function FieldFilterForm({
Expand All @@ -16,14 +16,30 @@ export default function FieldFilterForm({
const [value, setValue] = useState();
const { getFilters } = useFilters();
const { formatValue } = useFormat();
const { locale } = useLocale();
const filters = getFilters(type);

const formattedValues = useMemo(() => {
const formatted = {};
const format = val => {
formatted[val] = formatValue(val, name);
return formatted[val];
};
if (values.length !== 1) {
const { compare } = new Intl.Collator(locale, { numeric: true });
values.sort((a, b) => compare(formatted[a] ?? format(a), formatted[b] ?? format(b)));
} else {
format(values[0]);
}
return formatted;
}, [values]);

const renderFilterValue = value => {
return filters.find(f => f.value === value)?.label;
};

const renderValue = value => {
return formatValue(value, name);
return formattedValues[value];
};

const handleAdd = () => {
Expand Down Expand Up @@ -59,7 +75,7 @@ export default function FieldFilterForm({
}}
>
{value => {
return <Item key={value}>{formatValue(value, name)}</Item>;
return <Item key={value}>{formattedValues[value]}</Item>;
}}
</Dropdown>
</Flexbox>
Expand Down
10 changes: 7 additions & 3 deletions src/app/(main)/settings/users/UserAddButton.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { Button, Icon, Text, Modal, Icons, ModalTrigger } from 'react-basics';
import { Button, Icon, Text, Modal, Icons, ModalTrigger, useToasts } from 'react-basics';
import UserAddForm from './UserAddForm';
import useMessages from 'components/hooks/useMessages';
import { setValue } from 'store/cache';

export function UserAddButton({ onSave }) {
const { formatMessage, labels } = useMessages();
const { formatMessage, labels, messages } = useMessages();
const { showToast } = useToasts();

const handleSave = () => {
onSave();
showToast({ message: formatMessage(messages.saved), variant: 'success' });
setValue('users', Date.now());
onSave?.();
};

return (
Expand Down
2 changes: 1 addition & 1 deletion src/app/(main)/settings/websites/WebsiteSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function WebsiteSettings({ websiteId, openExternal = false, analyticsUrl

const handleReset = async value => {
if (value === 'delete') {
await router.push('/settings/websites');
router.push('/settings/websites');
} else if (value === 'reset') {
showSuccess();
}
Expand Down
3 changes: 1 addition & 2 deletions src/app/(main)/websites/[id]/WebsiteChartList.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Button, Text, Icon } from 'react-basics';
import { Button, Text, Icon, Icons } from 'react-basics';
import { useMemo } from 'react';
import { firstBy } from 'thenby';
import Link from 'next/link';
Expand All @@ -7,7 +7,6 @@ import useDashboard from 'store/dashboard';
import WebsiteHeader from './WebsiteHeader';
import { WebsiteMetricsBar } from './WebsiteMetricsBar';
import { useMessages, useLocale } from 'components/hooks';
import Icons from 'components/icons';

export default function WebsiteChartList({ websites, showCharts, limit }) {
const { formatMessage, labels } = useMessages();
Expand Down
2 changes: 1 addition & 1 deletion src/components/common/ErrorMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export function ErrorMessage() {

return (
<div className={styles.error}>
<Icon className={styles.icon} size="large">
<Icon className={styles.icon} size="lg">
<Icons.Alert />
</Icon>
<Text>{formatMessage(messages.error)}</Text>
Expand Down
6 changes: 3 additions & 3 deletions src/components/common/FilterLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import styles from './FilterLink.module.css';
export interface FilterLinkProps {
id: string;
value: string;
label: string;
externalUrl: string;
className: string;
label?: string;
externalUrl?: string;
className?: string;
children: ReactNode;
}

Expand Down
3 changes: 1 addition & 2 deletions src/components/common/HamburgerButton.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Button, Icon } from 'react-basics';
import { Button, Icon, Icons } from 'react-basics';
import { useState } from 'react';
import MobileMenu from './MobileMenu';
import Icons from 'components/icons';

export function HamburgerButton({ menuItems }: { menuItems: any[] }) {
const [active, setActive] = useState(false);
Expand Down
2 changes: 1 addition & 1 deletion src/components/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import User from 'assets/user.svg';
import Users from 'assets/users.svg';
import Visitor from 'assets/visitor.svg';

const icons: any = {
const icons = {
...Icons,
AddUser,
Bars,
Expand Down
5 changes: 0 additions & 5 deletions src/components/layout/PageHeader.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,4 @@
.header {
margin-bottom: 10px;
}

.actions {
flex-basis: 100%;
order: -1;
}
}
4 changes: 3 additions & 1 deletion src/components/metrics/FilterTags.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ import { safeDecodeURI } from 'next-basics';
import { Button, Icon, Icons, Text } from 'react-basics';
import useNavigation from 'components/hooks/useNavigation';
import useMessages from 'components/hooks/useMessages';
import useFormat from 'components/hooks/useFormat';
import styles from './FilterTags.module.css';

export function FilterTags({ params }) {
const { formatMessage, labels } = useMessages();
const { formatValue } = useFormat();
const {
router,
makeUrl,
Expand Down Expand Up @@ -34,7 +36,7 @@ export function FilterTags({ params }) {
return (
<div key={key} className={styles.tag} onClick={() => handleCloseFilter(key)}>
<Text>
<b>{`${key}`}</b> = {`${safeDecodeURI(params[key])}`}
<b>{formatMessage(labels[key])}</b> = {formatValue(safeDecodeURI(params[key]), key)}
</Text>
<Icon>
<Icons.Close />
Expand Down
4 changes: 4 additions & 0 deletions src/components/metrics/FilterTags.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@
.tag:hover {
background: var(--blue200);
}

.tag b {
text-transform: lowercase;
}
2 changes: 1 addition & 1 deletion src/lib/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ export function incrementDateRange(value, increment) {

const { num, unit } = selectedUnit;

const sub = num * increment;
const sub = Math.abs(num) * increment;

switch (unit) {
case 'hour':
Expand Down
13 changes: 9 additions & 4 deletions src/lib/detect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,16 @@ export async function getLocation(ip, req) {
const result = lookup.get(ip);

if (result) {
const country = result.country?.iso_code ?? result?.registered_country?.iso_code;
const subdivision1 = result.subdivisions?.[0]?.iso_code;
const subdivision2 = result.subdivisions?.[1]?.names?.en;
const city = result.city?.names?.en;

return {
country: result.country?.iso_code ?? result?.registered_country?.iso_code,
subdivision1: result.subdivisions?.[0]?.iso_code,
subdivision2: result.subdivisions?.[1]?.names?.en,
city: result.city?.names?.en,
country,
subdivision1: getRegionCode(country, subdivision1),
subdivision2,
city,
};
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/lib/middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ export const useAuth = createMiddleware(async (req, res, next) => {
} else if (redis.enabled && authKey) {
const key = await redis.client.get(authKey);

user = await getUserById(key?.userId);
if (key?.userId) {
user = await getUserById(key.userId);
}
}

if (process.env.NODE_ENV === 'development') {
Expand Down
16 changes: 8 additions & 8 deletions src/lib/prisma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ const POSTGRESQL_DATE_FORMATS = {
year: 'YYYY-01-01',
};

function getAddMinutesQuery(field: string, minutes: number): string {
function getAddIntervalQuery(field: string, interval: string): string {
const db = getDatabaseType(process.env.DATABASE_URL);

if (db === POSTGRESQL) {
return `${field} + interval '${minutes} minute'`;
return `${field} + interval '${interval}'`;
}

if (db === MYSQL) {
return `DATE_ADD(${field}, interval ${minutes} minute)`;
return `DATE_ADD(${field}, interval ${interval})`;
}
}

Expand Down Expand Up @@ -80,15 +80,15 @@ function getDateQuery(field: string, unit: string, timezone?: string): string {
}
}

function getTimestampIntervalQuery(field: string): string {
function getTimestampDiffQuery(field1: string, field2: string): string {
const db = getDatabaseType();

if (db === POSTGRESQL) {
return `floor(extract(epoch from max(${field}) - min(${field})))`;
return `floor(extract(epoch from (${field2} - ${field1})))`;
}

if (db === MYSQL) {
return `floor(unix_timestamp(max(${field})) - unix_timestamp(min(${field})))`;
return `timestampdiff(second, ${field1}, ${field2})`;
}
}

Expand Down Expand Up @@ -216,11 +216,11 @@ function getSearchMode(): { mode?: Prisma.QueryMode } {

export default {
...prisma,
getAddMinutesQuery,
getAddIntervalQuery,
getDayDiffQuery,
getCastColumnQuery,
getDateQuery,
getTimestampIntervalQuery,
getTimestampDiffQuery,
getFilterQuery,
parseFilters,
getPageFilters,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/yup.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import moment from 'moment';
import moment from 'moment-timezone';
import * as yup from 'yup';
import { UNIT_TYPES } from './constants';

Expand Down
2 changes: 1 addition & 1 deletion src/queries/analytics/eventData/getEventDataStats.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) {
async function clickhouseQuery(
websiteId: string,
filters: QueryFilters,
): Promise<{ events: number; fields: number; records: number }> {
): Promise<{ events: number; fields: number; records: number }[]> {
const { rawQuery, parseFilters } = clickhouse;
const { filterQuery, params } = await parseFilters(websiteId, filters);

Expand Down
12 changes: 6 additions & 6 deletions src/queries/analytics/getRealtimeData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ import { md5 } from 'next-basics';
import { getSessions, getEvents } from 'queries/index';
import { EVENT_TYPE } from 'lib/constants';

export async function getRealtimeData(websiteId, time) {
export async function getRealtimeData(websiteId: string, startDate: Date) {
const [pageviews, sessions, events] = await Promise.all([
getEvents(websiteId, time, EVENT_TYPE.pageView),
getSessions(websiteId, time),
getEvents(websiteId, time, EVENT_TYPE.customEvent),
getEvents(websiteId, startDate, EVENT_TYPE.pageView),
getSessions(websiteId, startDate),
getEvents(websiteId, startDate, EVENT_TYPE.customEvent),
]);

const decorate = (id, data) => {
return data.map(props => ({
const decorate = (id: string, data: any[]) => {
return data.map((props: { [key: string]: any }) => ({
...props,
__id: md5(id, ...Object.values(props)),
__type: id,
Expand Down
Loading

2 comments on commit f16d74e

@vercel
Copy link

@vercel vercel bot commented on f16d74e Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vercel
Copy link

@vercel vercel bot commented on f16d74e Dec 1, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.