diff --git a/.github/workflows/stale-issues.yml b/.github/workflows/stale-issues.yml index 24711fba..f1604014 100644 --- a/.github/workflows/stale-issues.yml +++ b/.github/workflows/stale-issues.yml @@ -22,3 +22,4 @@ jobs: operations-per-run: 200 ascending: true repo-token: ${{ secrets.GITHUB_TOKEN }} + exempt-issue-labels: bug,enhancement diff --git a/Dockerfile b/Dockerfile index 12951a73..801b2bc2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 . diff --git a/db/mysql/migrations/02_report_schema_session_data/migration.sql b/db/mysql/migrations/02_report_schema_session_data/migration.sql index 49708899..1649ace2 100644 --- a/db/mysql/migrations/02_report_schema_session_data/migration.sql +++ b/db/mysql/migrations/02_report_schema_session_data/migration.sql @@ -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` ( @@ -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; \ No newline at end of file +WHERE data_type = 4; diff --git a/docker-compose.yml b/docker-compose.yml index b8da9373..08f00b7c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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: diff --git a/package.json b/package.json index cf0398f7..ba85fb3e 100644 --- a/package.json +++ b/package.json @@ -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", @@ -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", diff --git a/src/app/(main)/reports/[id]/FieldFilterForm.js b/src/app/(main)/reports/[id]/FieldFilterForm.js index 96ac06b0..ea80f82a 100644 --- a/src/app/(main)/reports/[id]/FieldFilterForm.js +++ b/src/app/(main)/reports/[id]/FieldFilterForm.js @@ -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({ @@ -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 = () => { @@ -59,7 +75,7 @@ export default function FieldFilterForm({ }} > {value => { - return {formatValue(value, name)}; + return {formattedValues[value]}; }} diff --git a/src/app/(main)/settings/users/UserAddButton.js b/src/app/(main)/settings/users/UserAddButton.js index 8b691362..0f4bf734 100644 --- a/src/app/(main)/settings/users/UserAddButton.js +++ b/src/app/(main)/settings/users/UserAddButton.js @@ -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 ( diff --git a/src/app/(main)/settings/websites/WebsiteSettings.js b/src/app/(main)/settings/websites/WebsiteSettings.js index 71d5fe23..82b38048 100644 --- a/src/app/(main)/settings/websites/WebsiteSettings.js +++ b/src/app/(main)/settings/websites/WebsiteSettings.js @@ -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(); } diff --git a/src/app/(main)/websites/[id]/WebsiteChartList.js b/src/app/(main)/websites/[id]/WebsiteChartList.js index 23764dbb..bc2439de 100644 --- a/src/app/(main)/websites/[id]/WebsiteChartList.js +++ b/src/app/(main)/websites/[id]/WebsiteChartList.js @@ -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'; @@ -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(); diff --git a/src/components/common/ErrorMessage.tsx b/src/components/common/ErrorMessage.tsx index f8129c6b..0deb6f92 100644 --- a/src/components/common/ErrorMessage.tsx +++ b/src/components/common/ErrorMessage.tsx @@ -7,7 +7,7 @@ export function ErrorMessage() { return (
- + {formatMessage(messages.error)} diff --git a/src/components/common/FilterLink.tsx b/src/components/common/FilterLink.tsx index f91e1459..a9030227 100644 --- a/src/components/common/FilterLink.tsx +++ b/src/components/common/FilterLink.tsx @@ -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; } diff --git a/src/components/common/HamburgerButton.tsx b/src/components/common/HamburgerButton.tsx index 380392c8..5a81f3a3 100644 --- a/src/components/common/HamburgerButton.tsx +++ b/src/components/common/HamburgerButton.tsx @@ -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); diff --git a/src/components/icons.ts b/src/components/icons.ts index 8eb1f8b0..01d7caf5 100644 --- a/src/components/icons.ts +++ b/src/components/icons.ts @@ -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, diff --git a/src/components/layout/PageHeader.module.css b/src/components/layout/PageHeader.module.css index 8e615b93..a4eeb4c6 100644 --- a/src/components/layout/PageHeader.module.css +++ b/src/components/layout/PageHeader.module.css @@ -36,9 +36,4 @@ .header { margin-bottom: 10px; } - - .actions { - flex-basis: 100%; - order: -1; - } } diff --git a/src/components/metrics/FilterTags.js b/src/components/metrics/FilterTags.js index 554c223a..db8fdcbd 100644 --- a/src/components/metrics/FilterTags.js +++ b/src/components/metrics/FilterTags.js @@ -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, @@ -34,7 +36,7 @@ export function FilterTags({ params }) { return (
handleCloseFilter(key)}> - {`${key}`} = {`${safeDecodeURI(params[key])}`} + {formatMessage(labels[key])} = {formatValue(safeDecodeURI(params[key]), key)} diff --git a/src/components/metrics/FilterTags.module.css b/src/components/metrics/FilterTags.module.css index c228dc4e..32bc2f6f 100644 --- a/src/components/metrics/FilterTags.module.css +++ b/src/components/metrics/FilterTags.module.css @@ -24,3 +24,7 @@ .tag:hover { background: var(--blue200); } + +.tag b { + text-transform: lowercase; +} diff --git a/src/lib/date.ts b/src/lib/date.ts index a6c2b17b..51057309 100644 --- a/src/lib/date.ts +++ b/src/lib/date.ts @@ -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': diff --git a/src/lib/detect.ts b/src/lib/detect.ts index 3b2f9021..dab08312 100644 --- a/src/lib/detect.ts +++ b/src/lib/detect.ts @@ -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, }; } } diff --git a/src/lib/middleware.ts b/src/lib/middleware.ts index 5796009b..91fb6c7c 100644 --- a/src/lib/middleware.ts +++ b/src/lib/middleware.ts @@ -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') { diff --git a/src/lib/prisma.ts b/src/lib/prisma.ts index 4b910f00..2abf230c 100644 --- a/src/lib/prisma.ts +++ b/src/lib/prisma.ts @@ -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})`; } } @@ -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})`; } } @@ -216,11 +216,11 @@ function getSearchMode(): { mode?: Prisma.QueryMode } { export default { ...prisma, - getAddMinutesQuery, + getAddIntervalQuery, getDayDiffQuery, getCastColumnQuery, getDateQuery, - getTimestampIntervalQuery, + getTimestampDiffQuery, getFilterQuery, parseFilters, getPageFilters, diff --git a/src/lib/yup.ts b/src/lib/yup.ts index 5bd0aa18..4008e44f 100644 --- a/src/lib/yup.ts +++ b/src/lib/yup.ts @@ -1,4 +1,4 @@ -import moment from 'moment'; +import moment from 'moment-timezone'; import * as yup from 'yup'; import { UNIT_TYPES } from './constants'; diff --git a/src/queries/analytics/eventData/getEventDataStats.ts b/src/queries/analytics/eventData/getEventDataStats.ts index b940e9c4..39afa1ae 100644 --- a/src/queries/analytics/eventData/getEventDataStats.ts +++ b/src/queries/analytics/eventData/getEventDataStats.ts @@ -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); diff --git a/src/queries/analytics/getRealtimeData.ts b/src/queries/analytics/getRealtimeData.ts index 8786ab13..337e7475 100644 --- a/src/queries/analytics/getRealtimeData.ts +++ b/src/queries/analytics/getRealtimeData.ts @@ -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, diff --git a/src/queries/analytics/getWebsiteStats.ts b/src/queries/analytics/getWebsiteStats.ts index 654a09a9..4dbdb462 100644 --- a/src/queries/analytics/getWebsiteStats.ts +++ b/src/queries/analytics/getWebsiteStats.ts @@ -12,7 +12,8 @@ export async function getWebsiteStats(...args: [websiteId: string, filters: Quer } async function relationalQuery(websiteId: string, filters: QueryFilters) { - const { getDateQuery, getTimestampIntervalQuery, parseFilters, rawQuery } = prisma; + const { getDateQuery, getAddIntervalQuery, getTimestampDiffQuery, parseFilters, rawQuery } = + prisma; const { filterQuery, joinSession, params } = await parseFilters(websiteId, { ...filters, eventType: EVENT_TYPE.pageView, @@ -24,13 +25,16 @@ async function relationalQuery(websiteId: string, filters: QueryFilters) { sum(t.c) as "pageviews", count(distinct t.session_id) as "uniques", sum(case when t.c = 1 then 1 else 0 end) as "bounces", - sum(t.time) as "totaltime" + sum(case when t.max_time < ${getAddIntervalQuery('t.min_time', '1 hour')} + then ${getTimestampDiffQuery('t.min_time', 't.max_time')} + else 0 end) as "totaltime" from ( select website_event.session_id, - ${getDateQuery('website_event.created_at', 'hour')}, - count(*) as c, - ${getTimestampIntervalQuery('website_event.created_at')} as "time" + ${getDateQuery('website_event.created_at', 'day')}, + count(*) as "c", + min(website_event.created_at) as "min_time", + max(website_event.created_at) as "max_time" from website_event join website on website_event.website_id = website.website_id diff --git a/src/queries/analytics/reports/getFunnel.ts b/src/queries/analytics/reports/getFunnel.ts index 8dbd8d45..4387cf09 100644 --- a/src/queries/analytics/reports/getFunnel.ts +++ b/src/queries/analytics/reports/getFunnel.ts @@ -35,7 +35,7 @@ async function relationalQuery( }[] > { const { windowMinutes, startDate, endDate, urls } = criteria; - const { rawQuery, getAddMinutesQuery } = prisma; + const { rawQuery, getAddIntervalQuery } = prisma; const { levelQuery, sumQuery } = getFunnelQuery(urls, windowMinutes); function getFunnelQuery( @@ -58,9 +58,9 @@ async function relationalQuery( join website_event we on l.session_id = we.session_id where we.website_id = {{websiteId::uuid}} - and we.created_at between l.created_at and ${getAddMinutesQuery( + and we.created_at between l.created_at and ${getAddIntervalQuery( `l.created_at `, - windowMinutes, + `${windowMinutes} minute`, )} and we.referrer_path = {{${i - 1}}} and we.url_path = {{${i}}} diff --git a/src/queries/analytics/reports/getInsights.ts b/src/queries/analytics/reports/getInsights.ts index c5fac48b..a5b1b773 100644 --- a/src/queries/analytics/reports/getInsights.ts +++ b/src/queries/analytics/reports/getInsights.ts @@ -83,10 +83,17 @@ async function clickhouseQuery( limit 500 `, params, - ); + ).then(a => { + return Object.values(a).map(a => { + return { + x: a.x, + y: Number(a.y), + }; + }); + }); } -function parseFields(fields) { +function parseFields(fields: any[]) { const query = fields.reduce( (arr, field) => { const { name } = field; @@ -99,7 +106,7 @@ function parseFields(fields) { return query.join(',\n'); } -function parseGroupBy(fields) { +function parseGroupBy(fields: { name: any }[]) { if (!fields.length) { return ''; } diff --git a/yarn.lock b/yarn.lock index 2c95f0d3..1e405135 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1941,22 +1941,22 @@ "@parcel/watcher-win32-ia32" "2.3.0" "@parcel/watcher-win32-x64" "2.3.0" -"@prisma/client@5.4.2": - version "5.4.2" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.4.2.tgz#786f9c1d8f06d955933004ac638d14da4bf14025" - integrity sha512-2xsPaz4EaMKj1WS9iW6MlPhmbqtBsXAOeVttSePp8vTFTtvzh2hZbDgswwBdSCgPzmmwF+tLB259QzggvCmJqA== +"@prisma/client@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.6.0.tgz#1c15932250d5658fe0127e62faf4ecd96a877259" + integrity sha512-mUDefQFa1wWqk4+JhKPYq8BdVoFk9NFMBXUI8jAkBfQTtgx8WPx02U2HB/XbAz3GSUJpeJOKJQtNvaAIDs6sug== dependencies: - "@prisma/engines-version" "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574" + "@prisma/engines-version" "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee" -"@prisma/engines-version@5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574": - version "5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.4.1-2.ac9d7041ed77bcc8a8dbd2ab6616b39013829574.tgz#ff14f2926890edee47e8f1d08df7b4f392ee34bf" - integrity sha512-wvupDL4AA1vf4TQNANg7kR7y98ITqPsk6aacfBxZKtrJKRIsWjURHkZCGcQliHdqCiW/hGreO6d6ZuSv9MhdAA== +"@prisma/engines-version@5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee": + version "5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.6.0-32.e95e739751f42d8ca026f6b910f5a2dc5adeaeee.tgz#57b003ab5e1ea1523b5cdd7f06b24ebcf5c7fd8c" + integrity sha512-UoFgbV1awGL/3wXuUK3GDaX2SolqczeeJ5b4FVec9tzeGbSWJboPSbT0psSrmgYAKiKnkOPFSLlH6+b+IyOwAw== -"@prisma/engines@5.4.2": - version "5.4.2" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.4.2.tgz#ba2b7faeb227c76e423e88f962afe6a031319f3f" - integrity sha512-fqeucJ3LH0e1eyFdT0zRx+oETLancu5+n4lhiYECyEz6H2RDskPJHJYHkVc0LhkU4Uv7fuEnppKU3nVKNzMh8g== +"@prisma/engines@5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.6.0.tgz#82c445aa10633bbc0388aa2d6e411a0bd94c9439" + integrity sha512-Mt2q+GNJpU2vFn6kif24oRSBQv1KOkYaterQsi0k2/lA+dLvhRX6Lm26gon6PYHwUM8/h8KRgXIUMU0PCLB6bw== "@prisma/extension-read-replicas@^0.3.0": version "0.3.0" @@ -2601,10 +2601,10 @@ "@typescript-eslint/types" "6.8.0" eslint-visitor-keys "^3.4.1" -"@umami/prisma-client@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.5.0.tgz#e2287debbf21f9344c989b9e7192491df88513bf" - integrity sha512-BkStMrvxYZQPwEIyy30JJPucTTsmQqb4jD8+ciSHxcBc7039cW0XyX3TL/u9ebZmANzIuNO0XiBArwjWulGIjg== +"@umami/prisma-client@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@umami/prisma-client/-/prisma-client-0.7.0.tgz#f9de0dfc861c9ba6379c0789e012d4effa65f1ef" + integrity sha512-70Azr4aAYMU6c+Lx69bjumNnKWgOFoq2PuYmp+T2kfCDhMyMLXTLDVD5ArDrwJMl1gWsgvpnumxCirYy+6KhGg== dependencies: chalk "^4.1.2" debug "^4.3.4" @@ -3209,11 +3209,16 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001538, caniuse-lite@^1.0.30001541: version "1.0.30001551" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001551.tgz#1f2cfa8820bd97c971a57349d7fd8f6e08664a3e" integrity sha512-vtBAez47BoGMMzlbYhfXrMV1kvRF2WP/lqiMuDu1Sb4EE4LKEgjopFDSRtZfdVnslNRpOqV/woE+Xgrwj6VQlg== +caniuse-lite@^1.0.30001406: + version "1.0.30001558" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001558.tgz#d2c6e21fdbfe83817f70feab902421a19b7983ee" + integrity sha512-/Et7DwLqpjS47JPEcz6VnxU9PwcIdVi0ciLXRWBQdj1XFye68pSQYpV0QtPTfUKWuOaEig+/Vez2l74eDc1tPQ== + chalk@5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" @@ -7372,12 +7377,12 @@ pretty-bytes@^5.6.0: resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== -prisma@5.4.2: - version "5.4.2" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.4.2.tgz#7eac9276439ec7073ec697c6c0dfa259d96e955e" - integrity sha512-GDMZwZy7mysB2oXU+angQqJ90iaPFdD0rHaZNkn+dio5NRkGLmMqmXs31//tg/qXT3iB0cTQwnGGQNuirhSTZg== +prisma@5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.6.0.tgz#ae2c27fdfb4d53be7f7dafb50d6b8b7f55c93aa5" + integrity sha512-EEaccku4ZGshdr2cthYHhf7iyvCcXqwJDvnoQRAJg5ge2Tzpv0e2BaMCp+CbbDUwoVTzwgOap9Zp+d4jFa2O9A== dependencies: - "@prisma/engines" "5.4.2" + "@prisma/engines" "5.6.0" promise.series@^0.2.0: version "0.2.0" @@ -7471,10 +7476,10 @@ rc@^1.2.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -react-basics@^0.107.0: - version "0.107.0" - resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.107.0.tgz#e5615792cbb3e4707ba5c8f438b29d6a88cf38b3" - integrity sha512-jYnP1z2LTotxXWYwxOBvF26vXxSUBJB0x62YPKkEr1vmJGeg8iOLr8JGF8KE3R6E+NTqzRt6Bmdtt93mjaog4A== +react-basics@^0.109.0: + version "0.109.0" + resolved "https://registry.yarnpkg.com/react-basics/-/react-basics-0.109.0.tgz#9c1f41ebf6abbcf67f7dd11a16a7fb5e3aedd38d" + integrity sha512-n955CwqIeQ/sTMxxvbtYpWtBWS07Rg39zrNKeUYN/JoCIq0YbbZiZDALAhh1Out+qsIe62NoOFA7JtHzk1EkHQ== dependencies: "@react-spring/web" "^9.7.3" classnames "^2.3.1"